Controlling the size of a QScrollArea
-
Hey.
Consider the following:
WhereWidget C
is a parent ofWidget A
&Widget B
and installed withQVBoxLayout
, and all are subclasses ofQWidget
.Now, I want
Widget B
to take more space in height, but not on the expense ofWidget A
.
Something along the line of:
I tried re-implementing
Widget B
'sQSize sizeHint()const
:QSize WidgetB::sizeHint()const { QSize parentSize(QWidget::sizeHint()); return QSize(parentSize.width(), parentSize.height() + 500); }
Unfortunately, this had no effect.
On the other hand, re-implementing
QSize minimumSizeHint()const
did the trick:QSize WidgetB::minimumSizeHint()const { QSize parentSize(QWidget::minimumSizeHint()); return QSize(parentSize.width(), parentSize.height() + 500); }
But this is not a good solution for me, since I cannot resize
Widget C
(top level widget) because ofWidget B
minimum requirement.I want
Widget B
's size to start off with extended height, and let the user choose if they want to reduceWidget B
height by resizingWidget C
(which is the top level window).So; why is
QSize sizeHint()const
being ignored byWidget C
'sQVBoxLayout
?
How can I achieve the desired effect?Thanks.
-
@SGaist ok, I tried using stretch but this had no effect...
QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(_mainPanel); mainLayout->addWidget(_bottomPanel, 2); setLayout(mainLayout);
could it be related to some of the properties of
_mainPanel
(aka "Widget A") and_bottomPanel
(aka "Widget B")?
what am I missing here?Thanks.
-
Did you keep your sizeHint overloads ?
-
@SGaist OK! Progress! :)
Indeed, I had to keep the overload for thesizeHint()
and so I did, and nowQVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(_mainPanel); mainLayout->addWidget(_bottomPanel, 2); setLayout(mainLayout);
Together with this in
_bottomPanel
:QSize BottomPanel::sizeHint()const { QSize parentSize(QWidget::sizeHint()); return QSize(parentSize.width(), parentSize.height() + 500); }
Caused BottomPanel to be higher, but not by as much as I'd like.
So I tried increasing:mainLayout->addWidget(_bottomPanel, 4); // now it's 4
and:
QSize BottomPanel::sizeHint()const { QSize parentSize(QWidget::sizeHint()); return QSize(parentSize.width(), parentSize.height() + 800); // now it's 800 }
and it didn't grew further.
Can you please explain how exactly does the factor works?
The doc doesn't say much:The stretch factor applies only in the direction of the QBoxLayout, and is relative to the other boxes and widgets in this QBoxLayout. Widgets and boxes with higher stretch factors grow more.
If the stretch factor is 0 and nothing else in the QBoxLayout has a stretch factor greater than zero, the space is distributed according to the QWidget:sizePolicy() of each widget that's involved.
Nothing about the need to also re-implement
sizeHint()
...Thanks!
-
The thing is, you are putting your widgets in a QScrollArea. So depending on how you did configure things, the growth of your widgets might be impacted.
You should first get your widgets working as you want without the scroll area and then add it back to the mix.
-
@SGaist thanks for the consultant. Appreciate it.
Let me please start over, I will be more specific.
So what I currently have is this:
QWidgetBlack installed QVBoxLayout and added two widgets: QWidgetRedTop and QWidgetRedBottom.
QWidgetRedBottom installed QVBoxLayout and added QScrollAreaBlue
QScrollAreaBlue added QWidgetGreen usingQScrollAreaBlue::setWidget(QWidgetGreen)
(this here)Now, what I want is the app to start like this:
So, following your first advice, I did:
On QWidgetBlack:QVboxLayout* vbox = new QVBoxLayout; vbox->addWidget(QWidgetRedTop); vbox->addWidget(QWidgetRedBottom, 1); // with stretch
On QWidgetRedBottom:
QSize QWidgetRedBottom::sizeHint()const { // override QSize s = QWidget::sizeHint(); return QSize(s.width(), s.height() + 600); }
And indeed it stretched out the way I wanted, but not enough.
increasing both:vbox->addWidget(QWidgetRedBottom, 2); // with bigger stretch
and
QSize QWidgetRedBottom::sizeHint()const { // override QSize s = QWidget::sizeHint(); return QSize(s.width(), s.height() + 800); // now 800 instead of 600 }
did not make it grow any further.
Why is that? What am I doing wrong?
Thanks.
-
I think I found a similar question here, that also solves my predicament.
Quoting from there, the relevant part is:
So the most you can do is to define sizeHint and minimumSizeHint, set a stretch factor greater than all the others, and set a size-policy of Expanding. But even with all these things in place, it seems the layout manager is still not guaranteed to honour the size-hint when the minimum-size-hint is less.
The problem is that the definition of Expanding is not quite strong enough:The sizeHint() is a sensible size, but the widget can be shrunk and still be useful. The widget can make use of extra space, so it should get as much space as possible (e.g. the horizontal direction of a horizontal slider).
For whatever reason, the layout manager seems to prioritise shrinking over expanding if another widget has a stronger size-policy (e.g. Fixed). This looks like the wrong choice from the point of view of your example, but I suppose there may be other situations where it makes more sense. The behaviour seems to be exactly the same in both Qt4 and Qt5, so I don't know whether it should be considered a bug, or just a quirk of the implementation.
So I used the same workaround:
In QWidgetBlack:QVboxLayout* vbox = new QVBoxLayout; vbox->addWidget(QWidgetRedTop); vbox->addWidget(QWidgetRedBottom); // no need for stretch... setLayout(vbox); /* WA */ QWidgetRedBottom->setMinimumSize(QWidgetRedBottom->sizeHint()); adjustSize(); QWidgetRedBottom->setMinimumSize(QWidgetRedBottom->minimumSizeHint()); /******/
and it totally worked!
If anyone has comments/suggestions for a different solution I'd be happy to learn.