Qt: Как заставить скрытый виджет рассчитать свой макет?
Я пытаюсь сделать qwidget в другое окно (вручную используя QPainter)
У меня есть QWidget (w) с макетом и кучей дочерних элементов управления. w скрыт. Пока не будет показано w, не происходит никаких расчетов компоновки, что ожидается.
Когда я звоню w->render(painter, w->mapToGlobal(QPoint(0,0))
, я получаю кучу элементов управления, которые перекрывают друг друга.
w->layout()->activate();w->layout()->update()
ничего не делает.
Есть ли способ заставить макет произойти, не показывая w?
Ответы
Ответ 1
Принуждение вычисления компоновки виджета, не отображая его на экране:
widget->setAttribute(Qt::WA_DontShowOnScreen);
widget->show();
Вызов show()
заставит вычислять макет, а Qt::WA_DontShowOnScreen
гарантирует, что виджет явно не показан.
Ответ 2
Расчет макета виджета может быть принудительным, вызвав invalidate()
, а затем activate()
на его макете, даже если виджет скрыт. Это также приводит к тому, что функции виджетов size()
и sizeHint()
возвращают правильные и обновленные значения, даже если show()
еще не был вызван этим виджетами.
Однако необходимо заботиться обо всех дочерних виджетах и макетах рекурсивно, поскольку запрос перерасчета макета не распространяется автоматически на дочерние элементы.
В следующем коде показано, как это сделать.
/**
* Forces the given widget to update, even if it 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();
}
Ответ 3
Попробуйте использовать метод QWidget::sizeHint()
, который должен возвращать размер виджета, который был выложен.
Ответ 4
Это работало для меня при использовании sizeHint() плюс перевод живописца, однако я делаю это внутри метода 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();
}
В этом случае option.rect.topLeft()
дает мне правильное размещение. Вы должны попробовать более разумную координату вместо w->mapToGlobal(QPoint(0,0)
.
Ответ 5
У меня были некоторые успехи в аналогичной проблеме, сначала позвонив w->layout()->update()
до w->layout()->activate()
. Кажется, что заставить activ() фактически что-то делать, а не думать, что это нормально, потому что окно пока не отображается.