QDialog 對話框
非模态
QDialog * dlg = new QDialog()
dlg->show();
當然,這兒用指針(即配置設定到heap中)不是必須的。 (有疑問?或者有時發現視窗一閃而過?那麼你需要了解C、C++中變量的作用域和生存周期)。
模态
QDialog dlg;
dlg.exec();
這種情況下,我們一般都是将對象配置設定上 stack 上,而不是heap上。
當然,你喜歡用 heap,也沒問題:
Dialog * dlg = new QDialog();
dlg->exec();
delete dlg;
模态對話框
前面的 show() 與 exec() 并不是模态與非模态的差別。
想讓一個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()
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 當然是處于暫停狀态了。說到底,就是兩個死循環,一個在内,一個在外,隻有裡面的退出後,外邊的循環才會執行。不過由于兩個循環執行的指令是基本一樣的,都是調用并處理程式收到的各種事件,是以,可能變得不容易了解
參考:
https://www.yuque.com/docs/share/69c0ab8b-c33d-4629-8f17-f2fb5f956b27