Search code examples
c++qtlayoutqwidget

QLayout and discrete widget representation - how to?


Lets, for example, we have QHBoxLayout inside QMainWindow.

Lets we have set of the widgets inside above layout.

But (!) few of widgets have discrete visual representations. In another words they have few states dependent on available space.

For example:

  1. if there are too much available space - it must look like big image + some text
  2. if there available minimal space - it must look like little image
  3. if there available few more than minimal space - it must look like button + label
  4. etc...

So when the user change the main window size our "dynamic" widgets must show own representation dependent on available space.

How it could be achieved in Qt?

UPD: the closest behavior present in the Microsoft ribbon interface

UPD2: the QML closest behavior present in gif below (on part where window resized by user)

enter image description here

UPD3: more complex example - each panel in the menu panel change content elements view and count that depends from available space enter image description here


Solution

  • For this answer, I will use Qt-equivalent terms, not the official MS Ribbon terminology.

    An Overview

    You are actually looking at a number of layouts, in a pattern like so:

    QToolbar
    | (Layout)
    +--> QGroupBox/QToolButton
    |     | (Layout)
    |     +----->Button
    |     +----->Button
    +--> QGroupBox/QToolButton
    

    The Pattern

    Let's start with just the QGroupBox that populates helps sort our buttons into groups.

    Consider that our group box may hold both our dynamic QToolButton and regular widgets. When the available space shrinks, the layout:

    • Calculates the minimum space required for fixed-sized widgets and the minimumSizeHint() values of the widgets without fixed size policies.
    • Apportions the remaining space based on the growth policy of each widget.
    • However, our dynamic tool button may or may not change size depending on available space.
    • Now we have to start checking if the children of the layout are dynamic or not, using qobject_cast.
    • When we find a dynamic button, we have to determine if it can shrink or not. If it does, we cache this and its preferred, smaller size.
    • If it's going to shrink, we have to recalculate our minimum size.
    • And then we have to keep going, hoping that shrinking the buttons during resize doesn't cause any tricky tie-breakers.
    • Tie breakers: if two buttons can collapse to a smaller size, which one goess first? We have to account for that, too. Also, MS uses rows of three buttons. We can't collapse one from Qt::ToolButtonTextBesideIcon to Qt::ToolButtonIconOnly, we have to collapse a set of three.
    • Three horizontal buttons can collapse to three vertical buttons. This, too, needs to be calculated and cached.

    There is hope.

    We can simplify by making each container only able to hold dynamic tool buttons. Then we don't have to deal with tricky issues like fixed sized widgets and we only need to deal with one type of widget.

    Microsoft has also helpfully implemented this behavior for us. You can learn a lot about the behavioral constraints of your layout and child widgets by empirical observation. When do groups collapse? If a group collapses, do other groups expand to take up the space? (The answer to that is no, by the way.) How do buttons group together as they collapse? Are some special in how they collapse and expand (constraints on their expansion and collapsing behavior)?

    Qt has also implemented several layouts for us to study and get an idea of how they work and how they are different. QGridLayout is a promising basis, particularly if you do some math to change the row span of widgets on the fly (this is for grouping buttons as they collapse from vertical layout to sets of three horizontal buttons).

    In Summary

    Completely answering your question is far too broad to be on-topic on SO, but I hope this info guides you where you need to go.