Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt: How to force a hidden widget to calculate its layout?

What I am trying to do is render a qwidget onto a different window (manually using a QPainter)

I have a QWidget (w) with a layout and a bunch of child controls. w is hidden. Until w is shown, there is no layout calculations happening, which is expected.

When I call w->render(painter, w->mapToGlobal(QPoint(0,0)), I get a bunch of controls all overlapping each other.
w->layout()->activate();w->layout()->update() doesn't seem to do anything.

Is there a way to force the layout to happen without showing w?

like image 210
Chris Avatar asked Mar 11 '10 17:03

Chris


People also ask

How do I make a Qt widget invisible?

1) Subclass your QWidget and use a special/own setVisible() replacement method witch turns on/off the painting of the widget (if the widget should be invisible simply ignore the painting with an overridden paintEvent() method).

How do you hide the spacer in Qt?

Try putting the button you want to hide and unhide in another layout. In that layout along with the button put a spacer. Call Button hide and spacer will take over. Spacer takes over hidden button's space.

How do I add a horizontal spacer in Qt?

You can add a spacer item, either on the outside of your horizontal layout, or inside your horizontal layout. If you add the spacer item inside the horizontal layout, you have to make sure you add your label widgets before the spacer item. Use the insertWidget() function to add your labels in this case.


2 Answers

Forcing a layout calculation on a widget without showing it on the screen:

widget->setAttribute(Qt::WA_DontShowOnScreen);
widget->show();

The show() call will force the layout calculation, and Qt::WA_DontShowOnScreen ensures that the widget is not explicitly shown.

like image 101
Ton van den Heuvel Avatar answered Sep 19 '22 17:09

Ton van den Heuvel


The layout calculation of a widget can be forced by calling invalidate() followed by activate() on its layout, even if the widget is hidden. This also causes the widget's size() and sizeHint() functions to return correct and updated values, even if show() has not yet been called on that widget.

It is however necessary to care about all child widgets and layouts recursively, as a layout recalculation request doesn't automatically propagate to the childs.

The following code shows how to do this.

/**
 * Forces the given widget to update, even if it's hidden.
 */
void forceUpdate(QWidget *widget) {
    // Update all child widgets.
    for (int i = 0; i < widget->children().size(); i++) {
        QObject *child = widget->children()[i];
        if (child->isWidgetType()) {
            forceUpdate((QWidget *)child);
        }
    }

    // Invalidate the layout of the widget.
    if (widget->layout()) {
        invalidateLayout(widget->layout());
    }
}

/**
 * Helper function for forceUpdate(). Not self-sufficient!
 */
void invalidateLayout(QLayout *layout) {
    // Recompute the given layout and all its child layouts.
    for (int i = 0; i < layout->count(); i++) {
        QLayoutItem *item = layout->itemAt(i);
        if (item->layout()) {
            invalidateLayout(item->layout());
        } else {
            item->invalidate();
        }
    }
    layout->invalidate();
    layout->activate();
}
like image 29
emkey08 Avatar answered Sep 20 '22 17:09

emkey08