Some questions about understanding layout behavior
-
Hi, in general I understand how Qt layout work, I've read all needed documentation many times (about size policies, layout management etc). However sometimes I get weird layout behavior, which I cannot explain. Maybe I miss something about how layouts actually work?
Could you please tell me if I understand correctly the facts below:
- Layout sizeHint() is calculated as sum of all child widgets sizeHints + layout spacings + layout margins.
- Layout minimumSizeHint() is calculated as sum of all child widgets minimumSizeHints + layout spacings + layout_margins.
- Layout minimumSize is calculated as...? AND is used when we resize layout, the main widget cannot be smaller than minimumSize.
- Layout maximumSize is calculated as...? AND is used when we resize layout, the main widget cannot be larger than maximumSize.
- If there are N widgets with sizePolicy() = preferred and 1 widget with sizePolicy() = expanding, then the widget with expanding sizePolicy() should get all free space when the layout is resized, other widgets are stayed at their sizeHints().
- If the widget has layout, then its sizeHint() == layout sizeHint and minimumSizeHint() = layout minimumSizeHint.
- When there is useful to change layout size constraint?
- QWidget::setMinimumSize() causes layout recalculations?
Sometimes I get really weird layout behavious, for example I have the following widgets:
- Simple QPushButton (preferred size policy)
- My QWidget subclass which has proper sizeHint and minimumSizeHint (and preferred size policy)
- Vertical spacer (expanding size policy)
Then I put them into vertical layout and... When I resize the window (vertically) pushbutton doesn't change its size (it's ok since it has fixed height), but my QWidget subclass changes its height! Why? Why layout changes the sizes of my widget and spacer instead of changing only spacer size?
If I put QLabel instead of my qwidget subclass, and set its sizePolicy to Preferred - everything works as exptected.Here's some logs:
QLabel:
sizeHint = QSize(46, 13), minimumSizeHint = QSize(46, 13), size = QSize(378, 13), minimumSize = QSize(0, 0), maximumSize = QSize(16777215, 16777215)
Size Policy = preferredMy QWidget subclass:
sizeHint = QSize(204, 40), minimumSizeHint = QSize(164, 40), size = QSize(378, 387), minimumSize QSize(0, 0), maximumSize = QSize(16777215, 16777215)
Size Policy = preferredAs you can see, they both have adequate sizeHints, but QLabel is resized properly whereas "My QWidget subclass" gets more vertical space than needed.
Thanks.
-
Instead of a vertical spacer, do you get the desired resizing behavior if you use
yourLayout->addStretch(1)
I assume you are adding your widgets without specifying a stretch and alignment? If not, set the stretch to your widgets to 0. Also, I suggest you read (or re-read) Qt's layout documention, I found it gives a better overview of how to create a desired layout than just reading the individual documentation for the layout classes.
-
@mchinand said:
Instead of a vertical spacer, do you get the desired resizing behavior if you use
yourLayout->addStretch(1)
No, I don't. Currently I've rewritten all my widgets hierarchy in order to get it to work properly, but anyway the questions is still valid.
I assume you are adding your widgets without specifying a stretch and alignment? If not, set the stretch to your widgets to 0. Also, I suggest you read (or re-read) Qt's layout documention, I found it gives a better overview of how to create a desired layout than just reading the individual documentation for the layout classes.
Thanks for advice, but actually I've already read this documentation many times and I know it by heart ;) That's why I'm asking this question here from more experienced developers.
-
Hi,
@CppDev said:
Could you please tell me if I understand correctly the facts below:
- Layout sizeHint() is calculated as sum of all child widgets sizeHints + layout spacings + layout margins.
- Layout minimumSizeHint() is calculated as sum of all child widgets minimumSizeHints + layout spacings + layout_margins.
- Layout minimumSize is calculated as...? AND is used when we resize layout, the main widget cannot be smaller than minimumSize.
- Layout maximumSize is calculated as...? AND is used when we resize layout, the main widget cannot be larger than maximumSize.
I'm not sure about these.
- If there are N widgets with sizePolicy() = preferred and 1 widget with sizePolicy() = expanding, then the widget with expanding sizePolicy() should get all free space when the layout is resized, other widgets are stayed at their sizeHints().
Yes, I think so.
- If the widget has layout, then its sizeHint() == layout sizeHint and minimumSizeHint() = layout minimumSizeHint.
Not always. Different widgets have different rules for size hints. If you create a custom widget, you can choose your own rules by reimplementing QWidget::sizeHint() and QWidget::minimumSizeHint() -- notice that these are virtual functions. Qt's built-in widgets have their own rules.
But if you don't implement your own rules, then yes you're right. See http://doc.qt.io/qt-5/qwidget.html#sizeHint-prop : "The default implementation of sizeHint() returns an invalid size if there is no layout for this widget, and returns the layout's preferred size otherwise."
- When there is useful to change layout size constraint?
Have you seen http://doc.qt.io/qt-5/qlayout.html#SizeConstraint-enum ?
- QWidget::setMinimumSize() causes layout recalculations?
I think so. It needs to check if the current size is smaller than the minimum, and resize if necessary.
Sometimes I get really weird layout behavious, for example I have the following widgets:
- Simple QPushButton (preferred size policy)
- My QWidget subclass which has proper sizeHint and minimumSizeHint (and preferred size policy)
What do you mean by "proper sizeHint"? Did you implement the rules?
- Vertical spacer (expanding size policy)
Then I put them into vertical layout and... When I resize the window (vertically) pushbutton doesn't change its size (it's ok since it has fixed height), but my QWidget subclass changes its height! Why? Why layout changes the sizes of my widget and spacer instead of changing only spacer size?
If I put QLabel instead of my qwidget subclass, and set its sizePolicy to Preferred - everything works as exptected.Here's some logs:
QLabel:
sizeHint = QSize(46, 13), minimumSizeHint = QSize(46, 13), size = QSize(378, 13), minimumSize = QSize(0, 0), maximumSize = QSize(16777215, 16777215)
Size Policy = preferredMy QWidget subclass:
sizeHint = QSize(204, 40), minimumSizeHint = QSize(164, 40), size = QSize(378, 387), minimumSize QSize(0, 0), maximumSize = QSize(16777215, 16777215)
Size Policy = preferredAs you can see, they both have adequate sizeHints, but QLabel is resized properly whereas "My QWidget subclass" gets more vertical space than needed.
What's inside your custom widget?
-
@JKSH said:
Hi,
@CppDev said:
Could you please tell me if I understand correctly the facts below:
- Layout sizeHint() is calculated as sum of all child widgets sizeHints + layout spacings + layout margins.
- Layout minimumSizeHint() is calculated as sum of all child widgets minimumSizeHints + layout spacings + layout_margins.
- Layout minimumSize is calculated as...? AND is used when we resize layout, the main widget cannot be smaller than minimumSize.
- Layout maximumSize is calculated as...? AND is used when we resize layout, the main widget cannot be larger than maximumSize.
I'm not sure about these.
As well as me...
- If there are N widgets with sizePolicy() = preferred and 1 widget with sizePolicy() = expanding, then the widget with expanding sizePolicy() should get all free space when the layout is resized, other widgets are stayed at their sizeHints().
Yes, I think so.
But unfortunately it didn't work in such way in my situation with custom widget.
- When there is useful to change layout size constraint?
Have you seen http://doc.qt.io/qt-5/qlayout.html#SizeConstraint-enum ?
Yes, if I understood right - this property influences setting minimumSize and maximumSize for main widget.
- QWidget::setMinimumSize() causes layout recalculations?
I think so. It needs to check if the current size is smaller than the minimum, and resize if necessary.
Sometimes I get really weird layout behavious, for example I have the following widgets:
- Simple QPushButton (preferred size policy)
- My QWidget subclass which has proper sizeHint and minimumSizeHint (and preferred size policy)
What do you mean by "proper sizeHint"? Did you implement the rules?
No, I didn't. I meant that it has some sensible value.
- Vertical spacer (expanding size policy)
Then I put them into vertical layout and... When I resize the window (vertically) pushbutton doesn't change its size (it's ok since it has fixed height), but my QWidget subclass changes its height! Why? Why layout changes the sizes of my widget and spacer instead of changing only spacer size?
If I put QLabel instead of my qwidget subclass, and set its sizePolicy to Preferred - everything works as exptected.Here's some logs:
QLabel:
sizeHint = QSize(46, 13), minimumSizeHint = QSize(46, 13), size = QSize(378, 13), minimumSize = QSize(0, 0), maximumSize = QSize(16777215, 16777215)
Size Policy = preferredMy QWidget subclass:
sizeHint = QSize(204, 40), minimumSizeHint = QSize(164, 40), size = QSize(378, 387), minimumSize QSize(0, 0), maximumSize = QSize(16777215, 16777215)
Size Policy = preferredAs you can see, they both have adequate sizeHints, but QLabel is resized properly whereas "My QWidget subclass" gets more vertical space than needed.
What's inside your custom widget?
A QStackedWidget with 2 pages.
-
I've no idea why is it happening.
Also sometimes I encounter with such problem: I have a QScrollArea and a stacked widget inside it, every stacked widget has multiple widgets. The stacked widget gets the sizeHint of the greatest widget of course.
For instance widget sizeHints are (200, 300), (400, 500), (100, 200), the stacked widget sizeHint will be (400, 500). The minimumSize for all widgets is also has some decent value.
So the question: why on earth the actual size (QWidget::size()) of QStackedWidget and its internal widgets is actually much greater (for instance 600, 850)? How is it possible?
P.S.: All widgets has preferred sizePolicy.