QWidget設定layout時的延遲重新整理問題

Bing_Lee發表於2020-11-05

QWidget設定layout時的延遲重新整理問題

問題說明

我在給一個QWidget A設定layout後立刻呼叫layout內QWidget B的函式,此時並沒有重新整理A的geometry,程式碼如下:

void test()
{
    m_bWidget = new BWidget();
    m_layout = new QHBoxLayout();
    m_layout->addWidget(m_bWidget);
    
    //設定layout
    m_aWidget->setLayout(m_layout);
    //呼叫內部QWidget物件的函式
    m_bWidget->resize();
}

void BWidget::resize()
{
    //此時輸出的geometry並不是最新m_aWidget的geometry,而是之前該layout的geometry或0.
    qDebug()<<"this geometry top left: x = "<<this->geometry().topLeft().x()<<"y = "<<this->geometry().topLeft().y();
    qDebug()<<"this geometry bottom right: x = "<<this->geometry().bottomRight().x()<<"y = "<<this->geometry().bottomRight().y();
}

解決方法

在setlayout之後設定一個延時呼叫,setlayout內部執行該動作需要一定時間,所以解決辦法是寫一個槽函式延時呼叫resize(),程式碼如下:

void test()
{
    m_bWidget = new BWidget();
    m_layout = new QHBoxLayout();
    m_layout->addWidget(m_bWidget);
    
    //設定layout
    m_aWidget->setLayout(m_layout);
    //寫一個槽延時函式,這裡博主有測試500ms 50ms 10ms 0ms均無問題故最後取0,因為也是需要儘快重新整理。
    QTimer::singleShot(0, this, SLOT(slot_resizeBWidget()));
}

void slot_resizeBWidget()
{
    m_bWidget->resize();
}

導致原因

推測是由下邊這段函式中有什麼延時重新整理geometry導致的,有興趣可以查一下這段qt的原始碼。

/*!
    \fn void QWidget::setLayout(QLayout *layout)

    Sets the layout manager for this widget to \a layout.

    If there already is a layout manager installed on this widget,
    QWidget won't let you install another. You must first delete the
    existing layout manager (returned by layout()) before you can
    call setLayout() with the new layout.

    If \a layout is the layout manger on a different widget, setLayout()
    will reparent the layout and make it the layout manager for this widget.

    Example:

    \snippet examples/uitools/textfinder/textfinder.cpp 3b

    An alternative to calling this function is to pass this widget to
    the layout's constructor.

    The QWidget will take ownership of \a layout.

    \sa layout(), {Layout Management}
*/

void QWidget::setLayout(QLayout *l)
{
    if (!l) {
        qWarning("QWidget::setLayout: Cannot set layout to 0");
        return;
    }
    if (layout()) {
        if (layout() != l)
            qWarning("QWidget::setLayout: Attempting to set QLayout \"%s\" on %s \"%s\", which already has a"
                     " layout", l->objectName().toLocal8Bit().data(), metaObject()->className(),
                     objectName().toLocal8Bit().data());
        return;
    }

    QObject *oldParent = l->parent();
    if (oldParent && oldParent != this) {
        if (oldParent->isWidgetType()) {
            // Steal the layout off a widget parent. Takes effect when
            // morphing laid-out container widgets in Designer.
            QWidget *oldParentWidget = static_cast<QWidget *>(oldParent);
            oldParentWidget->takeLayout();
        } else {
            qWarning("QWidget::setLayout: Attempting to set QLayout \"%s\" on %s \"%s\", when the QLayout already has a parent",
                     l->objectName().toLocal8Bit().data(), metaObject()->className(),
                     objectName().toLocal8Bit().data());
            return;
        }
    }

    Q_D(QWidget);
    l->d_func()->topLevel = true;
    d->layout = l;
    if (oldParent != this) {
        l->setParent(this);
        l->d_func()->reparentChildWidgets(this);
        l->invalidate();
    }

    if (isWindow() && d->maybeTopData())
        d->topData()->sizeAdjusted = false;
}

相關文章