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