Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force layout update/resize when child it manages resizes?

Tags:

qt

I have a custom QTextEdit widget that has it's own resize grip in the corner. I can resize the text widget fine, however the layout it is inside does not change with the resizing of the text edit.

Is there a way to tell the managing layout to recalculate itself based on the independent change in size in one of its widgets?

like image 444
George Avatar asked May 25 '12 16:05

George


2 Answers

The layout respects the sizeHint() and minimalSizeHint() of its children (not their size()). So you should reimplement these two virtual methods and return the size you want to force. Whenever your size hint changes, you should call updateGeometry() on your own widget to trigger an update of the layout where the widget is placed in.

See documentation:

  • virtual QSize QWidget::sizeHint() const

    This property holds the recommended size for the widget.
    [...]

  • virtual QSize QWidget::minimumSizeHint() const

    This property holds the recommended minimum size for the widget.
    [...]
    QLayout will never resize a widget to a size smaller than the minimum size hint unless minimumSize() is set or the size policy is set to QSizePolicy::Ignore. If minimumSize() is set, the minimum size hint will be ignored.

So, to force a minimum size of your widget, implement minimumSizeHint() by returning your minimum size; to force a fixed size, implement both by returning the same size.

I also recommend reading the following section in the documentation page "Layout Management":

Custom Widgets in Layouts

When you make your own widget class, you should also communicate its layout properties. If the widget has a one of Qt's layouts, this is already taken care of. If the widget does not have any child widgets, or uses manual layout, you can change the behavior of the widget using any or all of the following mechanisms:

  • Reimplement QWidget::sizeHint() to return the preferred size of the widget.
  • Reimplement QWidget::minimumSizeHint() to return the smallest size the widget can have.
  • Call QWidget::setSizePolicy() to specify the space requirements of the widget.

Call QWidget::updateGeometry() whenever the size hint, minimum size hint or size policy changes. This will cause a layout recalculation. Multiple consecutive calls to QWidget::updateGeometry() will only cause one layout recalculation.


Update (see comments):

You can also force a size (or height / width only) by calling:

QWidget::setFixedSize(QSize);
QWidget::setFixedHeight(int);
QWidget::setFixedWidth(int);

These methods simply set the size hints to the given value and call updateGeometry() AFAIK. But maybe they do a little bit more since (as seen in the comments) this was the only way I could find to solve the problem here.

like image 66
leemes Avatar answered Sep 27 '22 22:09

leemes


The answer of leemes gave me some insight and I managed to achieve resize of a QTextWidget inside a layout among other controls using custom SizeGrip control. Note that at least one scroll bar should be visible in order to have visible size grip.

It was necessary to reimplement the widget's sizeHint() method:

QSize MultilineTextEdit::sizeHint() const
{
    return size();
}

Then at the end of mouseMoveEvent() of my SizeGrip widget I added

void SizeGrip::mouseMoveEvent(QMouseEvent * e)
{
    // note that this is not the full code of the method
    ...
    // save the old minimum and maximum size of the widget (w) resized by the grip
    QSize oldMin = w->minimumSize();
    QSize oldMax = w->maximumSize();

    w->setFixedSize(nr.size()); // nr is the new rect of the widget

    w->setMinimumSize(oldMin);
    w->setMaximumSize(oldMax);
}

The SizeGrip widget was inspired by the QSizeGrip class which operates on the top level parent window directly. SizeGrip operates on its direct parent widget instead.

like image 24
Uga Buga Avatar answered Sep 28 '22 00:09

Uga Buga