PDA

View Full Version : Has parent/child resizeEvent calling order changed since Qt5.1.1?



Kirinyale
16th July 2015, 18:06
I came back to my Qt project after a break and upgraded it from 5.1.1 to 5.5. Now I've found at least one feature that is broken for a reason I don't quite understand...

I have a dialog with an expanding QLabel. Layout is built in such a way that this label covers most of the dialog width with any reasonable size. I'm attaching a screenshot from Designer for clarity - the QLabel in question (tilesImage_) is selected.

For some reason, when QDialog::resizeEvent() gets called after creating the dialog, tilesImage_ still has wrong size (much smaller than it should be, e.g. 100x64 when the dialog is 688x411). My code relied on the fact that all widget sizes are properly updated at this point, and this definitely worked in Qt 5.1.1 (I just checked an old build). Apparently, something important changed between 5.1.1 and 5.5 in this regard. Is there any documentation about this change? Any workarounds (except installing an event filter to each separate widget I need to check)?

anda_skoa
17th July 2015, 10:08
This is strange.
The label is in a layout and its size policy is appropriate as well.

Does it work in designer's preview?

Cheers,
_

Kirinyale
17th July 2015, 10:27
Yes, it does (you can see its border marks on the screenshot too). Also, everything seems to work once I resize the open dialog manually at least once, but I'm not 100% sure if that's not just because of the small difference between old and new size values in that case (since manual resizing is gradual).

The code that depends on resizing is responsible for refreshing the image that is shown on that label (visually, it's a collection of selectable icons arranged in rows and columns), and, since its size is reported incorrectly, I only get 1 row and 1 column at first. This fixes itself after scrolling too, since it is another event that updates the image, this time with the correct size.

I'm uploading 2 more screenshots where this can be seen. "Bad" is what I get immediately after opening the dialogue, "good" is what it should be (and what it becomes after scrolling or resizing). Also, installing event filter directly onto the label did fix the issue, but I can imagine it occuring elsewhere, since everything hints at the event handling order as far as I can see...

anda_skoa
17th July 2015, 10:43
Yes, it does (you can see its border marks on the screenshot too).

No, I was referring to the preview function.



The code that depends on resizing is responsible for refreshing the image that is shown on that label (visually, it's a collection of selectable icons arranged in rows and columns), and, since its size is reported incorrectly, I only get 1 row and 1 column at first. This fixes itself after scrolling too, since it is another event that updates the image, this time with the correct size.

When do you attempt to read the size values?
Has the widget been shown at that time?

Cheers,
_

Kirinyale
17th July 2015, 11:11
No, I was referring to the preview function.
Ah, it works there too (though I had to add text and alignment to check, since otherwise the label is empty by default). The problem is not that it's not resizing (it does, eventually), it's that it's either resizing later than I expect, or its width() and height() methods report the new size later than I expect (which should be the same, I guess).


When do you attempt to read the size values?
Has the widget been shown at that time?
I'm reading them from inside QDialog::resizeEvent, called during QDialog::exec. I can imagine that the widget might not be "completely" shown at that point, but as the docs say, "When resizeEvent() is called, the widget already has its new geometry". Isn't the child widgets' geometry considered a logical part of the parent's geometry?

...Adding the same call to showEvent helped, by the way. Also checked that calling QDialog::resize manually later gives the expected result. So that's it, I guess. Thanks for the help!

I just wonder when and why was this behavior changed - it is a bit confusing for resizeEvent to work differently at different moments...

anda_skoa
17th July 2015, 13:14
I'm reading them from inside QDialog::resizeEvent, called during QDialog::exec.

Since you are interested in the label's size, why not react to its size changes?
IMHO the logical place to put your size handling code would be in the label's resizeEvent() method.



"When resizeEvent() is called, the widget already has its new geometry". Isn't the child widgets' geometry considered a logical part of the parent's geometry?

Yes and no. The layout will also try to affect the widget's geometry if necessary, i.e. if the new size can no longer accomodate the children's needs.
Above that size the children will be changed instead.

Cheers,
_

Kirinyale
17th July 2015, 13:30
Since you are interested in the label's size, why not react to its size changes?
IMHO the logical place to put your size handling code would be in the label's resizeEvent() method.
Because that would require creating a new class derived from QLabel and using it instead, so that I can overload its resizeEvent, and also providing it with access to all other application-specific data that is used for drawing. That seems like an awful lot of extra work for such a simple task. :) Of course, I'd certainly do it if I had to re-use the same drawing logic elsewhere, but for now it's just one dialog.

Anyway, an event filter (which I've already mentioned) does exactly the same with less hassle by redirecting label's resizeEvent to the dialog. But I can imagine situations where I'd need to update multiple things based on sizes of multiple widgets (all in the same dialog), so it would be very nice to have a single place where all such sizes are guaranteed to be up-to-date -- not just update everything when one widget changes, then update everything again because another one changed too, etc etc...

anda_skoa
17th July 2015, 13:58
Because that would require creating a new class derived from QLabel and using it instead

Well, implementing resizeEvent() might need a class, but it is the cleanest way to do it.
The event filter has a slightly different "view" of things, since it gets the event before the widget, so if the widget does anything in the event handler, the filter will not see that effect.



But I can imagine situations where I'd need to update multiple things based on sizes of multiple widgets (all in the same dialog), so it would be very nice to have a single place where all such sizes are guaranteed to be up-to-date -- not just update everything when one widget changes, then update everything again because another one changed too, etc etc...

Well, widgets can change their geometry, so you would need to "listen" on each widget you are interested in anyway, e.g. using an event filter, and then call the method that does use their sizes.

Can't really imagine what that would be needed for though.

Cheers,
_