PDA

View Full Version : QTreeWidget in QVBoxLayout



NIteLordz
31st January 2015, 23:23
I have two QTreeWidgets that are placed inside of a QVBoxLayout. However, when i collapse the QTreeWidget on top, the QTreeWidget on the bottom does not move up. I have a bottom border around the QTreeWidget and verified that the QTreeWidget on top collapses, as the bottom border moves up to the collapsed size.

GameObjectInspector and TransformInspector both are derived from QTreeWidget with nothing internally overridden.


QVBoxLayout* inspectorLayout = new QVBoxLayout();
inspectorLayout->setSpacing(0);
inspectorLayout->setContentsMargins(0, 0, 0, 0);

gameObjectInspector_ = new GameObjectInspector(context_, centralWidget_);
gameObjectInspector_->setVisible(false);

transformInspector_ = new TransformInspector(context_, centralWidget_);
transformInspector_->setVisible(false);

wysota
1st February 2015, 07:47
Where do you put the widgets in the layout?

NIteLordz
1st February 2015, 12:22
Where do you put the widgets in the layout?




void InspectorWindow::Create() {
window_ = new QMainWindow();
window_->setStyleSheet("QMainWindow { background-color: #c2c2c2; }");
window_->setContentsMargins(0, 0, 0, 0);
window_->setMinimumSize(300, 150);
window_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);

QVBoxLayout* inspectorLayout = new QVBoxLayout();
inspectorLayout->setSpacing(0);
inspectorLayout->setContentsMargins(0, 0, 0, 0);

centralWidget_ = new QWidget(window_);

gameObjectInspector_ = new GameObjectInspector(context_, centralWidget_);
gameObjectInspector_->setVisible(false);

transformInspector_ = new TransformInspector(context_, centralWidget_);
transformInspector_->setVisible(false);

cameraInspector_ = new CameraInspector(context_, centralWidget_);
cameraInspector_->setVisible(false);

componentInspector_ = new QWidget(window_);

inspectorLayout->addWidget(gameObjectInspector_);
inspectorLayout->addWidget(transformInspector_);
inspectorLayout->addWidget(cameraInspector_);

centralWidget_->setLayout(inspectorLayout);

window_->setCentralWidget(centralWidget_);

setWidget(window_);
}

wysota
1st February 2015, 12:31
What are the vertical size policies of respective widgets?

NIteLordz
1st February 2015, 13:14
They both are derived the same manner


setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);

wysota
1st February 2015, 15:28
Try changing the vertical policy to MinimumExpanding. If that doesn't work then it means there is something else wrong with your layout system which we can't see in the code you posted. In that case crafting a minimal compilable example reproducing the problem would be helpful.

NIteLordz
1st February 2015, 15:31
yea, once i get the rest of this part done, im going to create a PoC and see what is going on. thanks for the input, i have already tried all the QSizePolicies, but still having the issue. time to go bare bones and go from there.

NIteLordz
1st February 2015, 17:39
So i have created a minimal project, and in the attached screenshot, you can see that the two tree widgets are taking up 50% of the screen, even when collapsed. I know i can listen to the itemCollapsed signal, and then resize the TreeWidget to a height of 20, which collapses the red area, however, the space reserved in the layout (QVBoxLayout) still remains at 50% of the screen. I want that area to collapse as well.

Not posting the entire project as i have it built in VS 2013 and not sure what IDE you use normally. Thanks for any direction or input you can provide.

10933



ui.setupUi(this);
{
treeWidgetA_ = new QTreeWidget(this);
treeWidgetA_->setStyleSheet("QTreeWidget { background-color: red; }");
treeWidgetA_->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
treeWidgetA_->header()->close();

QTreeWidgetItem* parentItemA = new QTreeWidgetItem(treeWidgetA_);
parentItemA->setText(0, "A");
treeWidgetA_->addTopLevelItem(parentItemA);

QTreeWidgetItem* childItem0 = new QTreeWidgetItem(parentItemA);
childItem0->setText(0, "Child 0");
parentItemA->addChild(childItem0);
}

{
treeWidgetB_ = new QTreeWidget(this);
treeWidgetB_->setStyleSheet("QTreeWidget { background-color: blue; }");
treeWidgetB_->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
treeWidgetB_->header()->close();

QTreeWidgetItem* parentItemB = new QTreeWidgetItem(treeWidgetB_);
parentItemB->setText(0, "B");
treeWidgetB_->addTopLevelItem(parentItemB);

QTreeWidgetItem* childItem0 = new QTreeWidgetItem(parentItemB);
childItem0->setText(0, "Child 0");
parentItemB->addChild(childItem0);
}

QWidget* container = new QWidget(this);

QVBoxLayout* layout = new QVBoxLayout(container);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
layout->addWidget(treeWidgetA_);
layout->addWidget(treeWidgetB_);

container->setLayout(layout);

setCentralWidget(container);

wysota
1st February 2015, 21:17
I think we misunderstood each other. What exactly do you understand by the term that the "widget is collapsed"? Did you expect the red widget to shrink if its items are collapsed? That will not happen, the view does not automatically adjust to the space its items take -- collapsing and expanding items in a view have no influence on the size of the widget. I thought that you meant that you hide one widget and expect the other to take its space. That does work correctly as shown in this code (Qt5.4 and C++11 required to build):


#include <QtWidgets>

class MainWindow : public QMainWindow {
public:
MainWindow() {
treeWidgetA_ = new QTreeWidget;
treeWidgetA_->setStyleSheet("QTreeWidget { background-color: red; }");
treeWidgetA_->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
treeWidgetA_->header()->close();

QTreeWidgetItem* parentItemA = new QTreeWidgetItem(treeWidgetA_);
parentItemA->setText(0, "A");
treeWidgetA_->addTopLevelItem(parentItemA);

QTreeWidgetItem* childItem0 = new QTreeWidgetItem(parentItemA);
childItem0->setText(0, "Child 0");
parentItemA->addChild(childItem0);

treeWidgetB_ = new QTreeWidget;
treeWidgetB_->setStyleSheet("QTreeWidget { background-color: blue; }");
treeWidgetB_->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
treeWidgetB_->header()->close();

QTreeWidgetItem* parentItemB = new QTreeWidgetItem(treeWidgetB_);
parentItemB->setText(0, "B");
treeWidgetB_->addTopLevelItem(parentItemB);

childItem0 = new QTreeWidgetItem(parentItemB);
childItem0->setText(0, "Child 0");
parentItemB->addChild(childItem0);

QWidget* container = new QWidget;

QVBoxLayout* layout = new QVBoxLayout(container);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
layout->addWidget(treeWidgetA_);
layout->addWidget(treeWidgetB_);

setCentralWidget(container);

QTimer::singleShot(5000, [&]() { treeWidgetA_->hide(); });
}
private:
QTreeWidget *treeWidgetA_, *treeWidgetB_;
};

int main(int argc, char **argv) {
QApplication app(argc, argv);
MainWindow mw;
mw.show();
return app.exec();
}

NIteLordz
1st February 2015, 21:20
Yea, that is what i was guessing. How can i get the red area to shrink when the QTreeWidget collapses. I have been looking at the layout structures, and nothing is jumping out at me that i could trigger when itemCollapsed is emitted from the root item.

wysota
1st February 2015, 21:24
You still didn't explain what you mean by "QTreeWidget collapses". If you want to resize the widget then do just that. Whenever any of its items get expanded or collapsed, recalculate the size and update the sizeHint. However this is going to be really counter-intuitive to the user.

NIteLordz
1st February 2015, 21:28
I have two tree widgets. they both live in a layout. by default they each take up 50% of the layout, whether the tree widget needs that space or not, based on the items that are present in the tree widget respectively.

Given that Tree A has 3 items in it, it would fit inside the red area (in the screen shot above). when i "collapse" the tree widget, no children of Tree A are showing (this works). I was expecting the "area" in the layout to "collapse" as well, as it is not needed by Tree A anymore, until Tree A is expanded.

So i am trying to figure out how to have the area within the layout that Tree A has assigned to it, "collapse" when Tree A "collapses" its children items.

hope that helps clarify what i am trying to accomplish.

wysota
2nd February 2015, 00:36
I was expecting the "area" in the layout to "collapse" as well, as it is not needed by Tree A anymore, until Tree A is expanded.
What would you expect the widget to do if you had an item with 10000 children collapsed and then you expanded them all? Would the widget expand down through the floor to your neighbour downstairs? :)

What you want to do seems ok if you have three items. It will simply be useless if you have 200 items as you will not fit them all on screen anyway. Resizing the widget when some items get hidden is going to be a pain in the neck.


So i am trying to figure out how to have the area within the layout that Tree A has assigned to it, "collapse" when Tree A "collapses" its children items.

Layouts will not help you here. You have to do all the computations on your own and all the resizing on your own too. I can only say that the vertical scroll bar of the view contains the viewport size required to fit all the visible items.

NIteLordz
2nd February 2015, 01:39
No, it wouldn't expand down through the floor, i'd expect it to expand to the maximum height that is specified, and a scroll bar allowing for the rest to be viewable with.

So layouts aren't truly dynamic then ?

So how does it work if i "hide" a tree widget, that space then becomes usable by every other widget, as they move up properly, but if the tree widget is visible, collapsed, but visible, then it still requires all the space within the layout ?

From those details, it sounds like i need to refactor my code, to not use layouts as they will not provide the functionality. seems very limiting, as this is issue that occurs in many applications. Unity's inspector for one, when a tree is collapsed, windows explorer shows the same functionality.

thanks for the input, i will have to refactor, not a big deal.

wysota
2nd February 2015, 08:43
No, it wouldn't expand down through the floor, i'd expect it to expand to the maximum height that is specified, and a scroll bar allowing for the rest to be viewable with.
So when adding and removing items in the model your widgets would be suffering from epilepsy? :)


So layouts aren't truly dynamic then ?
They are dynamic, it is just the widget is not prepared to do what you want it to.

To do what you want to do you would have to provide minimumSizeHint and maximumSizeHint to the widget to set the minimum and maximum size allowed. Then you would have to set the size policy to Fixed as this is the only policy that forces your sizeHint to be respected, Then you would have to reimplement sizeHint() to return the exact size your widget should have in any moment. Remember to call updateGeometry() whenever you feel that sizeHint should be recalculated.

This will make the widget prepared to cooperate with the layout system. Of course this won't work if you put more than one such widget in the same layout -- if two widgets want to be 100px high and the surrounding widget is 500px high then there is a 300px gap none of the widgets want. You either agree to have the gap or you have to rethink your approach.


So how does it work if i "hide" a tree widget, that space then becomes usable by every other widget, as they move up properly, but if the tree widget is visible, collapsed, but visible, then it still requires all the space within the layout ?
There is no notion of "collapsing" widgets. Your tree view is programmed to be at least N pixels high and it does just that.

NIteLordz
2nd February 2015, 13:57
just an fyi by changing the QSizePolicy on TreeWidgetA from example above to MinimumExpanding and Fixed for height, and then capturing itemExpanded and itemCollapsed, and setting the respected heights, i was able to achieve what i wanted with having to rewrite.

Since my TreeWidgets have a known amount of items in there, the height can be pre calculated, and then when the tree is collapsed, the height is also known, so i am able to set the fixed height, and this auto updates the layout container, thus moving all widgets up in the layout.

wysota
2nd February 2015, 14:00
just an fyi by changing the QSizePolicy on TreeWidgetA from example above to MinimumExpanding and Fixed for height, and then capturing itemExpanded and itemCollapsed, and setting the respected heights, i was able to achieve what i wanted with having to rewrite.

Since my TreeWidgets have a known amount of items in there, the height can be pre calculated, and then when the tree is collapsed, the height is also known, so i am able to set the fixed height, and this auto updates the layout container, thus moving all widgets up in the layout.

Provided all your users use the same font family and size as you do.

NIteLordz
2nd February 2015, 14:01
this is not for distrubution, this is for an internal application.

granted modular code is always best, but this is easily extended, to provide accessor methods, to set the font height, and whatever other characteristics are needed to calculate the height on a per item basis.