2010-03-11 3 views
15

Was ich versuche ist, ein Qwidget in ein anderes Fenster zu rendern (manuell mit einem QPainter)Qt: Wie erzwinge ich ein verstecktes Widget, um sein Layout zu berechnen?

Ich habe ein QWidget (w) mit einem Layout und einer Reihe von untergeordneten Steuerelementen. w ist versteckt. Bis w angezeigt wird, gibt es keine Layout-Berechnungen, die erwartet werden.

Als ich w->render(painter, w->mapToGlobal(QPoint(0,0)) anrufe, bekomme ich ein paar Kontrollen alle einander überlappen.
w->layout()->activate();w->layout()->update() scheint nichts zu tun.

Gibt es eine Möglichkeit, das Layout zu zwingen, ohne w zeigt geschehen?

Antwort

15

Erzwingen einer Layout-Berechnung auf einem Widget, ohne sie auf dem Bildschirm zeigt:

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

Der show() Aufruf der Layoutberechnung zwingen wird, und Qt::WA_DontShowOnScreen sorgt dafür, dass das Widget nicht explizit dargestellt ist.

+2

Verspäteter Dank, das funktioniert perfekt! – Chris

+0

Beachten Sie, dass ein Widget nur dann sichtbar wird, wenn alle seine Vorfahren ebenfalls sichtbar sind. Wenn dies nicht der Fall ist, löst das Aufrufen von 'show()' das Problem hier möglicherweise nicht. Siehe meine Antwort unten für einen anderen Ansatz, der immer funktionieren sollte. – emkey08

+1

@MathiasKunter Dennoch sollte angemerkt werden, dass Paint-Ereignisse perfekt zum "gezeigten" (aber nicht auf dem Bildschirm sichtbaren) Widget fließen, wenn Sie, sagen wir, ein paar Mausklicks einspeisen (im Gegensatz zum einfachen elternlosen Widget)! – mlvljr

1

Versuchen Sie, mit dem QWidget::sizeHint() Methode, die die Größe des Widgets einmal angelegt zurückkehren soll.

+0

Ich habe versucht, das, und es tat mir wieder vernünftige Größen geben .. aber es hat nicht die Positionen aktualisieren! So sehen die Größen richtig aus, aber sie sind immer noch übereinander. – Chris

0

Das ist für mich gearbeitet, wenn die sizeHint mit() und den Maler zu übersetzen, aber ich dies tun in der Farbe() -Methode.

void ParentWidget::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const 
{ 
    painter->save(); 
    painter->translate(option.rect.topLeft()); 
    w->render(painter); 
    painter->restore(); 
} 

In diesem Fall gibt option.rect.topLeft() mir die richtige Platzierung. Sie sollten eine sinnvollere Koordinate anstelle von w->mapToGlobal(QPoint(0,0) versuchen.

0

hatte ich einig Erfolg in einem ähnlichen Problem, indem man zuerst w->layout()->update() vor w->layout()->activate() Aufruf. Das scheint das activate() dazu zu zwingen, tatsächlich etwas zu tun, anstatt zu denken, dass es in Ordnung ist, weil das Fenster sowieso nicht angezeigt wird.

10

Die Layoutberechnung eines Widgets kann erzwungen werden, indem invalidate() gefolgt von activate() auf seinem Layout aufgerufen wird, auch wenn das Widget ausgeblendet ist. Dies führt auch dazu, dass die Funktionen size() und sizeHint() des Widgets korrekte und aktualisierte Werte zurückgeben, auch wenn show() noch nicht für dieses Widget aufgerufen wurde.

Es ist jedoch notwendig, rekursiv alle untergeordneten Widgets und Layouts kümmern uns um, wie ein Layout Neuberechnung Anfrage nicht automatisch auf die Childs propagieren.

Der folgende Code zeigt, wie Sie dies tun.

/** 
* 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(); 
} 
+0

Das 'layout-> invalidate(); layout-> activate(); 'funktionierte bei mir für eine etwas andere Anwendung: Erzwingen der Größenänderung eines bereits sichtbaren Layouts nach dem Hinzufügen/Entfernen eines Widgets. – Onlyjus

Verwandte Themen