Important: Please read the Qt Code of Conduct -

[SOLVED] Resizing QVBoxLayout without changing content size but changing spacing

  • Hi,
    I've got a QWidget with a QGridLayout. It contains about 10 QTextEdits and on the bottom a QPushButton and a QCheckBox. On click on the button new QTextEdits should be stored in a new column, so I need a QGridLayout..
    Now I have two different problems:

    1. How can I set a starting height to the QTextEdits? The QTextEdits are too big (to high) by default, so I'd like to set a default height to them. Problem is, I only see functions like setMinimumHeight(int) or setMaximumHeight(int), but that is not what I want. Using setGeometry() needs also x and y position, that is also not what I need...

    2. When user changes QWidget by mouse-click down on the QWidget border and enlarging it --> my QTextEdits grow. That is also an effect I would like to avoid. I know that this must be possible, because my QPushButton and my QCheckBox don't grow, instead, they just move with the border.
      Is it possible to have the same effect on the QTextEdits, like when user enlarges the Window, only the spacing between these Edits grows but not the Edits itsself? I think of setting RowStretch of QTextEdits to zero and then adding a strechable thing that is not visible between them... but how can I do that? (I hope it's not necessary to solve this by catching the resizeEvent and manually adding bigger space and fixing QTextEdit every time...)

    To question 2:
    Using QBoxLayouts, there is a very nice function called "addStretch()", what exactly does what I need. It inserts an invisible thing that is stretchable... But how can I manage that with QGridLayout which has no function like that? Also I miss the function insertWidget(QWidget*), because I'd like to insert the new QTextEdits at a specific index...
    Do I really have to solve this with multiple QVBoxLayouts in a QHboxLayout?? That would be really sad..
    Also I still don't have a solution for the default size of the QTextEdits...

    Thank you in anticipation!

  • Moderators

    If you don't want the text boxes to resize then use setFixedSize() on them. Then you don't need any stretches.

  • The problem with that is, that the window should be resizable by the user. If that happens and the user enlarges the window, anything has to be stretched. Now, when I use fixed sizes for QTextEdits, they are fixed in the window on top and the only thing that stretches is the QLabel over the QPushButton. That is not really the effect I'd like to have. What would look much better is when the spacing between the QTextEdits would stretch, so every QTextEdit would move relative to the enlarging window.
    Is there a hack to do that in a QGridLayout or do I have to manage this with nested QVBoxLayouts --> addStretch()?

  • Moderators

    It does exactly what you want. There must be something else wrong with your layout. Can you show the code that creates it?

  • Sure:
    @this->layout_g = new QGridLayout();

    this->layout_h = new QHBoxLayout();
    this->label_columns = new QLabel("Persons:");
    this->button_add_person = new my_QPushButton("+");
    connect(this->button_add_person, SIGNAL(clicked()), this, SLOT(addEdit()));
    this->button_remove_person = new my_QPushButton("-");
    connect(this->button_remove_person, SIGNAL(clicked()), this, SLOT(removeEdit()));
    this->layout_g->addLayout(layout_h, 0, 0, 1, 1);
    for(int i = 0; i < 11; i++)
      this->list_edits.append(new QTextEdit());
      this->layout_g->addWidget(list_edits.last(), i+1, 0, 1, 1);
    this->label_rows = new QLabel("Row Counter:");
    this->layout_g->addWidget(label_rows, this->layout_g->rowCount(), 0, 1, 1);
    this->spinbox_rows = new QSpinBox();
    this->layout_g->addWidget(spinbox_rows, this->layout_g->rowCount(), 0, 1, 1);
    this->spinbox_rows->setRange(1, 10000);
    this->button_create = new QPushButton("Create Table");
    this->layout_g->addWidget(button_create, this->layout_g->rowCount(), 0, 1, 1);
    connect(this->button_create, SIGNAL(clicked()), this->instance_parent, SLOT(applySettings()));
    this->checkbox_savesettings = new QCheckBox("Save Settings");
    this->layout_g->addWidget(checkbox_savesettings, this->layout_g->rowCount(), 0, 1, 1);

    After running this example, when I try to enlarge the window by pulling down the bottom border, only the second QLabel ("Row Counter:") stretches and fills the new gained place in the window, what looks really bad, because it centers the text and so the label moves up away from the QSpinBox... very bad..
    Unfortunatelly, the block with the 10 QTextEdits is fixed with fixed spacing between them.
    Btw.: The window is a QDialog, but I don't think that it matters...

  • Moderators

    bq. only the second QLabel (“Row Counter:”) stretches and fills the new gained place in the window

    That's because the label is the only element in that layout that doesn't have fixed height. If you give it one ( setFixedHeight(XX) ) then the layout won't have any element to stretch and will start to increase padding between elements.

    Btw. You don't have to stick this-> in front of everythig, this is implicit in member functions. Also you don't need to keep a pointer to every element in your class eg. layouts tht you will never refer to later. You can make them local eg.
    auto layout_g = new QGridLayout();
    setLayout(layout_g); //no longer need layout_g variable, the thing it points to is managed by the parent now

  • So that means that setting an explicit size to a QWidget has a higher priority then stretching, but setting a stretchFactor '0' to every QWidget (as it is by default) has a lower priority and Qt picks out a victim that will although be stretched? According to which rules does Qt pick out the QWidget that will be stretched in case of no specific size settings and all QWidgets have the default strechFactor '0'? Does it take the first QWidget of the window or what is the algorithm then?
    To my mind Qt should also stretch the spacings between the QWidgets in that case, as long as programmer doesn't pass a definite stretchFactor to a QWidget...

  • Moderators

    It goes more or less like this (separately in vertical and horizontal):

    1. Add minimum sizes specified for all items in a layout, then add minimum spacing between them specified for the layout, then grow the window if it's too small to fit everything
    2. Subtract the sum of minimal spacing from the window size. That's the available space for layout items.
    3. Subtract from it the sum of all items that have fixed size. That's the space available for growing items.
    4. Split the available space between growing items using stretch factor. The name "stretch factor" is not very good. It really is share factor or available space fraction. For example if one item has stretch factor 3 and the other 5 then the first gets 3/8 of the space and the other 5/8. 0 acts more or less like 1. if all items have factor 0 the space gets thus distributed equally.
    5. Distribute any space left by adding equal fractions to the spacing between items. Notice that this step only takes place if there are no growing items in the layout. Otherwise they take all the space and there's nothing left to divide.

  • Ahh there we go, thank you! I'm again wondering from where did you get all that knowlege? I mean or I bet, that algorithms like this one are not written in any Qt documentation I can find in the internet, or do I only have the wrong websites?

    Such interesting stuff!

  • Moderators

    Well it's not an official algorithm. It's just how I came to think about it and it works 90% of the time. It doesn't take into consideration all the settings like minimum and maximum sizes or size hints/policies. The official steps are explained "here": but I find them a little confusing and not as easy to reason about in simple cases such as yours.

  • Look, I was wrong again, there is a description in the documentation :-P
    Well, you're right it's a bit more confusing than yours, so thank's again.

Log in to reply