QDialog 模態(tài)對(duì)話框與事件循環(huán)
本文關(guān)鍵詞:模態(tài),由筆耕文化傳播整理發(fā)布。
起源
qtcn中文論壇中有網(wǎng)友問到:
假設(shè)程序正常運(yùn)行時(shí),只有一個(gè)簡單的窗體A,此時(shí)只有一個(gè)GUI主線程,在這個(gè)主線程中有一個(gè)事件循環(huán)處理窗體上的事件。當(dāng)此程序運(yùn)行到某階段時(shí),彈出一個(gè)模態(tài)窗體B(書上說模態(tài)窗體是有其自己的事件循環(huán)的),此時(shí)模態(tài)窗體B是否會(huì)有一個(gè)對(duì)應(yīng)的子線程處理其事件循環(huán)?這兒其實(shí)有兩個(gè)問題:
題外:
如果進(jìn)一步呢?其實(shí)我們還可以說:
兩種常規(guī)用法:
非模態(tài) QDialog * dlg = new QDialog() dlg->show();當(dāng)然,這兒用指針(即分配到heap中)不是必須的。 (有疑問?或者有時(shí)發(fā)現(xiàn)窗口一閃而過?那么你需要了解C、C++中變量的作用域和生存周期)
模態(tài) QDialog dlg; dlg.exec();這種情況下,我們一般都是將對(duì)象分配上 stack 上,而不是heap上。
當(dāng)然,你喜歡用 heap,也沒問題:
Dialog * dlg = new QDialog(); dlg->exec(); delete dlg; 模態(tài)對(duì)話框前面的 show() 與 exec() 并不是模態(tài)與非模態(tài)的區(qū)別。
想讓一個(gè)Widget成為模態(tài),我們只需要對(duì)其設(shè)置:
setAttribute(Qt::WA_ShowModal, true);注意:這是QWidget的成員函數(shù) ,也就是說,QWidget可以顯示為模態(tài)或非模態(tài)!
setWindowModality除了直接調(diào)用setAttribute外,QWidget 提供了一個(gè)易用的函數(shù),來設(shè)置窗體的模態(tài)。其源碼如下:
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); }注意:該函數(shù)的參數(shù)取值:NonModal、WindowModal、ApplicationModal 分別對(duì)應(yīng)默認(rèn)情況下的
如果你沒有使用QDialog::open()的需求,你可能也不需要該函數(shù)。
setModal除了QWidget提供的成員,QDialog 提供了 setModal 的成員函數(shù),,我們看看其代碼:
void QDialog::setModal(bool modal) { setAttribute(Qt::WA_ShowModal, modal); }不用解釋了吧?我們要顯示模態(tài)對(duì)話框,只需要類似下面的代碼:
QDialog * dlg = new QDialog(); dlg->setAttribute(Qt::WA_ShowModal, true); dlg->show(); exec()有問題是不?為啥exec() 直接可以顯示模態(tài)對(duì)話框呢?看QDialog源代碼吧
int QDialog::exec() { Q_D(QDialog); ... setAttribute(Qt::WA_ShowModal, true); ... show(); ... QEventLoop eventLoop; (void) eventLoop.exec(QEventLoop::DialogExec); ... }看到答案沒:exec() 先設(shè)置modal屬性,而后調(diào)用 show() 顯示對(duì)話框,最后啟用事件循環(huán)
事件循環(huán)Qt 程序時(shí)事件驅(qū)動(dòng)的,每個(gè)程序,我們需要調(diào)用 QApplication::exec() 來啟用事件循環(huán)。
int QCoreApplication::exec() { ... QEventLoop eventLoop; int returnCode = eventLoop.exec(); ... return returnCode; }用前面的 QDialog::exec() 一樣,都是調(diào)用的 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); }進(jìn)一步:這將調(diào)用平臺(tái)相關(guān)的函數(shù),比如在windows下
bool QGuiEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) { if (!QEventDispatcherWin32::processEvents(flags)) return false; if (configRequests) // any pending configs? qWinProcessConfigRequests(); return true; }事件循環(huán)和線程沒有必然的聯(lián)系,事件循環(huán)可以用在QThread中,而且從Qt4.4開始,QThread的run函數(shù)默認(rèn)就調(diào)用了自己的事件循環(huán)。
對(duì)與QDialog來說,當(dāng)它自己的QEventLoop啟用時(shí),主程序的 QEventLoop 當(dāng)然是處于暫停狀態(tài)了。說到底,就是兩個(gè)死循環(huán),一個(gè)在內(nèi),一個(gè)在外,只有里面的退出后,外邊的循環(huán)才會(huì)執(zhí)行。不過由于兩個(gè)循環(huán)執(zhí)行的命令是基本一樣的,都是調(diào)用并處理程序收到的各種事件,所以,可能變得不容易理解
本文關(guān)鍵詞:模態(tài),由筆耕文化傳播整理發(fā)布。
本文編號(hào):234342
本文鏈接:http://sikaile.net/jianzhugongchenglunwen/234342.html