PDA

View Full Version : How to delay the layout-ing of a QGridLayout, until all widgets are visible?



mchl.nix
21st January 2020, 16:08
Hello,

I'm currently using PySide2, Qt 5.12.0

I implemented something like a tree structure, using a QGridLayout. The rows of the tree consist of 5-10 widgets, which are mostly labels. But I might have dozens or hundreds of rows in that layout. Most of them are hidden, but the tree and sub trees can be expanded, sometimes showing hundreds of widgets in one go.

As far as I understand, for each widget.setVisible(True) call, the layout is invalidated and corrected, which leads to a substantial slowdown in the seconds. I worked around that, by setting a QTimer on the setGeometry method of the QGridLayout, reseting the timer every time a call is made and only after 20ms of "silence" is the actual setGeometry called by me.

That works reasonably well, except, that in those 20ms and for a bit longer, the widgets are shown in their old place - sometimes at (0, 0) if they are shown the first time - and block the rest of the widgets. I figure, since I block their placement with my workaround, they are just shown wherever they happen to be with whatever size they happen to have.

Delaying the paint event doesn't work for me, since their child widgets receive their own paint events, independently and even if not, the background, which is done using the QPalette, is also independent of the paint event.

I also read about Qt::WA_WState_ExplicitShowHide, but I'm not quite sure, if this would help me in this situation.

So I have a few questions:

Is the slowdown of several seconds in a QGridLayout with ~100 visible Widgets to be expected, or am I doing something wrong (on top of implementing a tree structure this way)?
Is there a way to tell the layout to hang tight until all the widgets are set to visible and the widgets to stay hidden, until the layout has moved them correctly?
Is the slowdown caused by the widgets needing to size themselves, or by the layout needing to move them around?
Is there an alternative layout strategy, that could support my type of use case, or is that just out of the realm of possibility?

I didn't use a TreeView, because I wanted every sub tree to have their own header and field positions.

I hope I described everything well enough, that code won't be necessary, since it would be a lot.

d_stranz
21st January 2020, 18:58
Laying out the grid is part of the geometry calculations that take place prior to anything being shown, so it isn't possible to show the widgets -before- their sizes and positions have been calculated by the layout and its container. Blocking the setGeometry() calls in the way you do is undoubtedly preventing that process from working correctly, which is why you have widgets appearing in odd places.

Each time you change the visibility status of a widget, the layout -must- be recalculated in response, so there is no way to avoid that either. Changing the visibility probably results in a resizeEvent() as well as an eventual paintEvent() if the widget is made visible. Layouts are likely monitoring resizeEvent() for the widgets they manage, which in turn triggers a geometry recalculation.

You could try calling blockSignals() but I do not know how much of the layout calculation is the result of signals or the result of events.

mchl.nix
22nd January 2020, 11:11
Is there then a way, to make the layouting/size calculation easier for the widgets and the layout? For example, all rows will have the same height, but I'm unsure on how to communicate that to the grid layout.

d_stranz
22nd January 2020, 15:57
I'm unsure on how to communicate that to the grid layout.

I think the layout management uses the sizeHint() among other parameters in calculating geometry. You may get some help from this documentation (https://doc.qt.io/qt-5/layout.html) and these examples (https://doc.qt.io/qt-5/examples-layouts.html). In particular, the Flow Layout example shows how to implement a custom layout manager, which might give you some insights into how and when the geometry calculations are performed.

You might find that implementing your own layout is the best way to optimize performance for your specific case.