2010-03-11 12 views
15

Lo que intento hacer es renderizar un qwidget en una ventana diferente (manualmente usando un QPainter)Qt: ¿Cómo forzar un widget oculto para calcular su diseño?

Tengo un QWidget (w) con un diseño y un grupo de controles secundarios. w está escondido Hasta que se muestre w, no hay cálculos de diseño, lo que se espera.

Cuando llamo al w->render(painter, w->mapToGlobal(QPoint(0,0)), obtengo un grupo de controles superpuestos entre sí.
w->layout()->activate();w->layout()->update() parece que no hace nada.

¿Hay alguna manera de forzar el diseño sin mostrar w?

Respuesta

15

Forzar a un cálculo del esquema de un widget sin mostrarlos en la pantalla:

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

La llamada show() obligará al cálculo del esquema, y ​​Qt::WA_DontShowOnScreen asegura que el widget no se muestra explícitamente.

+2

¡Gracias tardías, eso funciona perfectamente! – Chris

+0

Tenga en cuenta que un widget solo será visible si todos sus antecesores también son visibles. Si este no es el caso, llamar a 'show()' podría no resolver el problema aquí. Vea mi respuesta a continuación para un enfoque diferente que siempre debería funcionar. – emkey08

+1

@MathiasKunter Aún así, debe tenerse en cuenta que los eventos de pintura fluyen perfectamente al widget "mostrado" (pero no visible en la pantalla) si, por ejemplo, le da algunos clics de ratón (a diferencia del widget simple sin padres). – mlvljr

1

Pruebe con el método QWidget::sizeHint(), que se supone devuelve el tamaño del widget una vez establecido.

+0

Lo intenté, y me devolvió los tamaños razonables ... ¡pero no actualizó las posiciones! Entonces, los tamaños se ven bien, pero aún están uno encima del otro. – Chris

0

Esto funcionó para mí cuando uso el sizeHint() más la traducción del pintor, sin embargo hago esto dentro del método paint().

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

En este caso, option.rect.topLeft() me coloca en la ubicación correcta. Debe intentar una coordenada más sensible en lugar de w->mapToGlobal(QPoint(0,0).

0

Tuve cierto éxito en un problema similar al llamar primero a w->layout()->update() antes de w->layout()->activate(). Eso parece forzar a la activación() a hacer algo en vez de pensar que está bien porque la ventana no se muestra de todos modos.

10

El cálculo del diseño de un widget se puede forzar llamando al invalidate() seguido de activate() en su diseño, incluso si el widget está oculto. Esto también hace que las funciones size() y sizeHint() del widget devuelvan valores correctos y actualizados, incluso si aún no se ha llamado a show() en ese widget.

Sin embargo, es necesario ocuparse de todos los widgets y diseños secundarios recursivamente, ya que una solicitud de cálculo de diseño no se propaga automáticamente a los elementos secundarios.

El siguiente código muestra cómo hacerlo.

/** 
* 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

El 'layout-> invalidate(); layout-> activate(); 'trabajado para mí para una aplicación ligeramente diferente: forzar el cambio de tamaño de un diseño ya visible después de agregar/eliminar un widget. – Onlyjus

Cuestiones relacionadas