關於Qt模態窗口的設置

QWidget 模態

模態窗口會阻止其他窗口的輸入型事件(如獲取焦點),但是模態窗口的子窗口不會被限制。

(設置 setAttribute(Qt::WA_showModal, true); 的方式Qt4.5已廢棄,略過)

目前,Qt中設置窗口模態是通過 QWidget 的 setWindowModality() 函數:

參數有三種枚舉:

  • Qt::NonModal :(=0)表示該窗口不是模態窗口,不會阻止其他窗口的輸入。
  • Qt::WindowModal :(=1)表示該窗口是單個窗口層次結構的模態,會阻止輸入到其父窗口,所有祖父母窗口以及其父窗口和祖父母窗口的所有同級窗口。(說人話就是這個模態窗口對象樹上的都被阻止了,除了自己的孩子,對象樹就是這個模態框得設置 parent,不然是阻塞不了別的窗口的)
  • Qt::ApplicationModal :(=2)表示該窗口是應用程序的模態窗口,會阻止本應用所有窗口的輸入。

(注意,Qt::WindowModal 的窗口你得設置 parent, 不然你也阻塞不了誰啊,畢竟他只會坑爹,遇到不認識的就唯唯諾諾) 

QDialog 模態

QDialog 是 QWidget 的派生類,不同於 QWidget 的默認無模態,QDialog 有三種情況:

  • 調用 show() 顯示:此時的模態屬性是根據你 setWindowModality 設置的模式來決定的。或者你可以設置 QDialog::setModal(bool model) ,爲 false(默認 false)則表示 Qt::NonModal ,爲 true 則表示 Qt::ApplicationModal 。
  • 調用 exec() 顯示:此時會忽略你設置的模態屬性,默認以 Qt::ApplicationModal 顯示,阻塞整個應用的窗口交互,並且會同步等待返回值。
  • 調用 open() 顯示:此時會忽略你設置的模態屬性,默認以 Qt::WindowModal 顯示,但是是異步處理,立即返回的。

相關源碼賞析:

int QDialog::exec()
{
    Q_D(QDialog);

    if (Q_UNLIKELY(d->eventLoop)) {
        qWarning("QDialog::exec: Recursive call detected");
        return -1;
    }

    bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose);
    setAttribute(Qt::WA_DeleteOnClose, false);

    d->resetModalitySetByOpen();

    bool wasShowModal = testAttribute(Qt::WA_ShowModal);
    setAttribute(Qt::WA_ShowModal, true);
    setResult(0);

    show();

    QPointer<QDialog> guard = this;
    if (d->nativeDialogInUse) {
        d->platformHelper()->exec();
    } else {
        QEventLoop eventLoop;
        d->eventLoop = &eventLoop;
        (void) eventLoop.exec(QEventLoop::DialogExec);
    }
    if (guard.isNull())
        return QDialog::Rejected;
    d->eventLoop = nullptr;

    setAttribute(Qt::WA_ShowModal, wasShowModal);

    int res = result();
    if (d->nativeDialogInUse)
        d->helperDone(static_cast<QDialog::DialogCode>(res), d->platformHelper());
    if (deleteOnClose)
        delete this;
    return res;
}

void QDialog::open()
{
    Q_D(QDialog);

    Qt::WindowModality modality = windowModality();
    if (modality != Qt::WindowModal) {
        d->resetModalityTo = modality;
        d->wasModalitySet = testAttribute(Qt::WA_SetWindowModality);
        setWindowModality(Qt::WindowModal);
        setAttribute(Qt::WA_SetWindowModality, false);
#ifdef Q_OS_MAC
        setParent(parentWidget(), Qt::Sheet);
#endif
    }

    setResult(0);
    show();
}

參考

Qt 文檔:https://doc.qt.io/qt-5/qt.html#WindowModality-enum

Qt 文檔:https://doc.qt.io/qt-5/qdialog.html#modal-prop

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章