2010-03-11 4 views
15

내가 뭘 하려는지 QWindget을 다른 창 (수동으로 QPainter 사용)에 렌더링하는 것입니다.Qt : 숨겨진 위젯이 레이아웃을 계산하도록 강제하는 방법?

레이아웃과 여러 개의 자식 컨트롤이있는 QWidget (w)가 있습니다. w가 숨겨져 있습니다. w가 표시 될 때까지 예상되는 레이아웃 계산이 없습니다.

w->render(painter, w->mapToGlobal(QPoint(0,0))을 호출하면 서로 겹치는 컨트롤이 하나씩 표시됩니다.
w->layout()->activate();w->layout()->update()은 아무 것도하지 않는 것 같습니다.

w를 표시하지 않고 레이아웃을 강제로 수행 할 수있는 방법이 있습니까?

답변

15

화면에 표시하지 않고 위젯의 레이아웃 계산 강제.

+2

감사합니다. 완벽하게 작동합니다! – Chris

+0

위젯은 모든 조상이 표시 될 때만 표시됩니다. 이것이 사실이 아니라면,'show()'를 호출하면 문제가 해결되지 않을 수도 있습니다. 항상 작동해야하는 다른 접근 방식에 대한 내 대답을 참조하십시오. – emkey08

+1

@MathiasKunter 그래도 주목해야 할 점은 페인트 위저드가 평범한 부모없는 위젯과는 달리 마우스로 몇 번의 클릭 만하면 페인트 이벤트가 완벽하게 "표시된"(그러나 화면에 보이지 않는) 위젯으로 흐르고 있다는 것입니다! – mlvljr

1

QWidget::sizeHint() 메서드를 사용해보십시오.이 메서드는 일단 배치 된 위젯의 크기를 반환합니다.

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

show() 호출 레이아웃 계산을 강제하며, Qt::WA_DontShowOnScreen 위젯 명시 적으로 도시되지 않는다는 것을 보장한다 :

+0

나는 그것을 시도했다. 그리고 그것은 나에게 적당한 크기를 돌려 줬다.. 그러나 그것은 위치를 최신 정보로 제공하지 않았다! 그래서 크기가 적당 해 보이지만 그들은 여전히 ​​서로의 위에 있습니다. – Chris

0

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) 대신에 더 합리적인 좌표를 시도해야합니다.

0

w->layout()->activate() 전에 먼저 w->layout()->update()을 호출하여 유사한 문제가 발생했습니다. 그것은 실제로 윈도우가 어쨌든 표시되지 않기 때문에 괜찮다고 생각하지 않고 activate()가 실제로 무언가를하도록 강요하는 것 같습니다.

10

위젯이 숨겨진 경우에도 invalidate()을 호출하고 레이아웃을 activate()으로 호출하면 위젯의 레이아웃 계산을 강제 수행 할 수 있습니다. 또한 show()이 아직 해당 위젯에서 호출되지 않은 경우에도 위젯의 size()sizeHint() 함수가 정확하고 업데이트 된 값을 반환합니다.

그러나 레이아웃 재 계산 요청이 자동으로 하위에 전파되지는 않으므로 모든 하위 위젯과 레이아웃을 재귀 적으로주의해야합니다.

다음 코드는이를 수행하는 방법을 보여줍니다.

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

'layout-> invalidate(); layout-> activate();는 약간 다른 응용을 위해 나를 위해 일했다 : 위젯을 추가/제거한 후에 이미 보이는 레이아웃의 크기를 강제적으로 변경했다. – Onlyjus

관련 문제