想讓一個Widget成為模態,我們只需要對其設置:
setAttribute(Qt::WA_ShowModal, true);
注意:這是QWidget的成員函數 ,也就是說,QWidget可以顯示為模態或非模態!
setWindowModality
除了直接調用setAttribute外,QWidget 提供了一個易用的函數,來設置窗體的模態。其源碼如下:
void QWidget::setWindowModality(Qt::WindowModality windowModality) { data->window_modality = windowModality; // setModal_sys() will be called by setAttribute() setAttribute(Qt::WA_ShowModal, (data->window_modality != Qt::NonModal)); setAttribute(Qt::WA_SetWindowModality, true); }
注意:該函數的參數取值:NonModal、WindowModal、ApplicationModal 分別對應默認情況下的
- QDialog::show()
- QDialog::open()
- QDialog::exec()
如果你沒有使用QDialog::open()的需求,你可能也不需要該函數。
setModal
除了QWidget提供的成員,QDialog 提供了 setModal 的成員函數,我們看看其代碼:
void QDialog::setModal(bool modal) { setAttribute(Qt::WA_ShowModal, modal); }
不用解釋了吧?我們要顯示模態對話框,只需要類似下面的代碼:
QDialog * dlg = new QDialog(); dlg->setAttribute(Qt::WA_ShowModal, true); dlg->show();
exec()
有問題是不?為啥exec() 直接可以顯示模態對話框呢?看QDialog源代碼吧
int QDialog::exec() { Q_D(QDialog); ... setAttribute(Qt::WA_ShowModal, true); ... show(); ... QEventLoop eventLoop; (void) eventLoop.exec(QEventLoop::DialogExec); ... }
看到答案沒:exec() 先設置modal屬性,而后調用 show() 顯示對話框,最后啟用事件循環
事件循環
Qt 程序時事件驅動的,每個程序,我們需要調用 QApplication::exec() 來啟用事件循環。
int QCoreApplication::exec() { ... QEventLoop eventLoop; int returnCode = eventLoop.exec(); ... return returnCode; }
用前面的 QDialog::exec() 一樣,都是調用的 QEventLoop::exec()
int QEventLoop::exec(ProcessEventsFlags flags) { Q_D(QEventLoop); ... while (!d->exit) processEvents(flags | WaitForMoreEvents | EventLoopExec); ... return d->returnCode; }
而
bool QEventLoop::processEvents(ProcessEventsFlags flags) { Q_D(QEventLoop); if (!d->threadData->eventDispatcher) return false; if (flags & DeferredDeletion) QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); return d->threadData->eventDispatcher->processEvents(flags); }
進一步:這將調用平台相關的函數,比如在windows下
bool QGuiEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) { if (!QEventDispatcherWin32::processEvents(flags)) return false; if (configRequests) // any pending configs? qWinProcessConfigRequests(); return true; }
事件循環和線程沒有必然的聯系,事件循環可以用在QThread中,而且從Qt4.4開始,QThread的run函數默認就調用了自己的事件循環。
對與QDialog來說,當它自己的QEventLoop啟用時,主程序的 QEventLoop 當然是處於暫停狀態了。說到底,就是兩個死循環,一個在內,一個在外,只有里面的退出后,外邊的循環才會執行。不過由於兩個循環執行的命令是基本一樣的,都是調用並處理程序收到的各種事件,所以,可能變得不容易理解
http://doc.qt.io/qt-4.8/qwidget.html