Understand Layouts and widgets

  • Hi all,

    i try to understand the play between layouts and widgets, so i have a general question:

    I have a QWidget and a QLayout, the layout is connected to the widget with QWidget->setLayout(QLayout).
    Now i want to understand what is happening:

    Does the layout tells the widget the geometry or is the widget telling the layout the possible geometry for this connected layout?
    What is happening if the layout isnt connected, and later (after i added some widgets/layouts to the layout) the layout gets connected?
    When i call QWidget->setLayout(QLayout), the QWidget becomes the parent of the layout, so this very clear. But i want to understand too,
    what is with children there dont have a parent widget?

    Thanks for a explanation :-)

  • Moderators

    Hi, welcome to devnet.

    I suggest you have a read of the Layout Management. It will answer many of your questions.

    To shortly address your questions:

    First, please don't use word connected when talking about layouts. The connection (signals/slots) mechanism is separate topic unrelated to layouts. The layout is set on a widget and widgets can be added to the layout.

    A layout itself does not have a geometry (it's not derived from QWidget). It only tells the widget it is set on the minimum required space to fit the widgets added to that layout (plus any margins and spacing it has). It also manages the geometry of all the widgets added to it.

    When a widget does not have a layout set it doesn't care about the geometry of its children i.e. it will not move/resize them when it is resized. It will also clip them if their position falls out of its boundaries.

    When a layout is set on a widget the widget will adjust its size if the minimum space required by widgets added to that layout is larger than current geometry. In other words it will grow to the required minimum if needed. By default it will not shrink automatically unless all the widgets in the layout have fixed size (set by the size policy or min/max size properties). Both of these are also true when widgets are added to the layout after the layout is set on some widget.

    When a layout is set on a widget the layout is re-parented and the widget becomes the parent of the layout. Also, all the widgets added to that layout (either before or after) are re-parented and the parent widget of the layout becomes their parent too. Note that the layout itself does not become the parent of the widgets added to it.

    If a layout has no parent (i.e. is not yet set on any widget) the widgets added to it are not re-parented. When such layout is later set on a widget that widget becomes the parent of the layout and all the widgets added to it.

    Deleting a layout does not delete the widgets added to it (as their parent is not the layout itself but the parent widget of the layout). The widgets added to a layout are destroyed when the parent of the layout is destroyed. If the layout had no parent the widgets will leak if not destroyed in other way.

    All in all you can think of a layout as sort of a proxy object that is not part of the widget stack but sort of "governs it from a side". I hope this is helpful. For more info please refer to the documentation I linked or ask.

  • Hi Chris,

    thanks a lot, sorry for the word "connected" - it is more my english but understanding of the Qt framework ;-)

    To be more clear: does the layout call methods on the parent widget (too) to adjust the parent widget's size if its not
    a sublayout?

    1.) add a label to a layout
    2.) call setLayout on a widget
    3.) the label's and layout's parent is now the widget

    Example of my (1) understanding:
    4.) the parent widget itself becomes now the size from the layout ?

    Example of my (2) understanding:
    4.) the layout is set to the possible size the widget can give the layout ?

    Sorry again for my bad english - i hope to be more clear.

  • Moderators

    First a small correction again: You said "the layout is set to the possible size (..)". As I mentioned a layout does not have a size itself nor a graphical representation at all. It is not a widget. It's a QObject that governs geometries of some widgets so it can't be resized. It can only react to the resizing of the parent or its contents and forward it up or down modified appropriately for its type (grid, vbox etc.).

    4.) Is not so simple. Depending on some conditions various things can happen. Some of these can be:

    • If the widget is not visible when 2.) happens, and then it is shown, it will be sized at the size recommended by the layout. In this case, because the label is the only widget in the layout this will be the size hint returned by the label ( + any margin defined in the layout).
    • If the widget is visible at the time of 2.) and the label has fixed size (i.e. by using setFixedSize(), setting same min/max sizes or a fixed size policy) then similarly the widget will be resized to the size of the label (again, + margins).
    • If in the previous case the widget has a fixed size too, then it will not be resized and any leftover space will be added to the margins inside it or, if the child is larger than the parent, the child will be clipped. this scenario is of course unrealistic because I can't think of reason to set a fixed size child larger than its fixed size parent. What's the point?

    If neither the widget nor the label is fixed size and they are both visible at the time of 2.) then what happens depends on the size policies of both label and the widget. By default a label and a widget have both vertical and horizontal size policy set to "preferred", which means there is a preferred size for them (e.g. the size needed to fit text in case of a label) but they can grow if there's a space remaining. So what will happen can be:

    • If the parent is smaller than the preferred size of the label (returned by its sizeHint()) it will grow to accommodate it (+ layout margins).
    • if the parent is the exact size of preferred label size + margins, it will obviously stay the same size
    • if the parent is larger than what label requires it will not resize. In this case the label will be resized to fill the parent (- margins), because the "preferred" policy allows it.

    Depending on size policies, size limitations (min/max), layout type, layout margins, padding, styles, stylesheets and other factors I certainly forgot there will be more or less dramatic variations on the behavior I described.

    Not to get lost in possibilities the 2 rules of thumb that work in most simple cases are:
    If it's the first time a widget is shown it will try to take only the minimum required to fit the children governed by its layout if it has any.
    If the widget is visible and you add layout to it or some stuff to layout it already has then it will grow to fit the children or the children will grow to fill the parent.

  • OMG, i doubt i've understood the most of layout functions, but your explanations cleans up a lot of my (mis-)understandings - many thanks again :-D

    So as you explain, as example the methods "setGeometry(QRect)" both on a layout and widget are only called from layouts but never from widgets to layouts. it makes sense now ;-)

  • Moderators

    Well I might have not been entirely truthful saying a layout has no size. After all it is a QLayoutItem and, as you pointed out, it has a setGeometry method. What I should have said is you shouldn't think about a layout in these terms.
    There is rarely a case where you would manipulate a size of a layout directly or care about it at all, unless you're for example implementing your own layout, which is rare. You either change the size of the parent or the children and the layout with its (let's call it "virtual") size is a sort of bookkeeping mean to calculate the dependencies of parent and children. You can think of it as sorta "the magic that needs to happen", but I personally treat it as a publicly documented implementation detail :)

Log in to reply

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.