熟悉的陌生人
Qt 是事件驅動的,所以當你用Qt的時候,幾乎時時刻刻和 QEventLoop 打交道、,只是你可能沒有意識到:
- QCoreApplicaton::exec()
- QApplication::exec()
- QDialog::exec()
- QThread::exec()
- QDrag::exec()
- QMenu::exec()
- ...
在前面列出的這些常見函數的背後,都有各自的QEventLoop,可能是我們很少有機會想到自己顯式使用QEventLoop的緣故吧,對這個類似乎總是有些陌生。
在 如何讓 Qt 程序的 Sleep 和 QDialog 模態對話框與事件循環 兩個短文中,我們可以看到 QEventLoop 的使用。那麼?如何自己使用 QEventLoop 的,又有什麼用呢?
QEventLoop
Manual 中說的很簡潔
At any time, you can create a QEventLoop object and call exec() on it to start a local event loop. From within the event loop, calling exit() will force exec() to return.
在任何時候,你都可以創建一個QEventLoop的對象,然後調用它的exec() 來開始一個局部的事件循環。
看Manual容易讓人頭大,那麼,看例子吧:
讓主線程等待100ms?
直接sleep一下行麼,顯然,如果你的用戶不介意你的程序界面不響應用戶操作,沒問題!可是如果介意呢?
此時,開啓一個局部的事件循環,讓其執行100ms後自己退出,似乎很不錯。寫來看看:
QEventLoop eventloop; QTimer::singleShot(100, &eventloop, SLOT(quit())); eventloop.exec();
- 創建事件循環
- 啓動定時器,讓其100ms後觸發事件循環的quit()槽
- 啓動事件循環
注:讓主線程等待有其他方法,此處略過。
窗口一閃而過?
不少人遇到過這個問題:在一個槽函數內創建了一個窗口對象,卻沒有看到窗口彈出來,或者看到窗口一閃而過。比如:
void XXXX::slot1() { QDialog dlg; dlg.show() }
當然,大家都知道原因:因爲到了後面的大括號處,dlg因爲出作用域,會被析構掉。解決方法很簡單,增大w的生存時間即可。比如:
- 將 dlg 作爲類的成員,而不是函數的局部變量
- 將 dlg 前面添加 static,作爲靜態成員
- 將 dlg 用 new 分配到 heap 中
- ...
能否用 QEventLoop 來解決呢?答案是,可以
void XXXX::slot1() { QDialog dlg; dlg.show() QEventLoop loop; connect(&dlg, SIGNAL(finished(int)), &loop, SLOT(quit())); loop.exec(QEventLoop::ExcludeUserInputEvents); }
恩至此,問題解決。其實,這也是 QDialog::exec() 內部所做的事情,只不過此處不是模態對話框而已。
博文索引 持續更新中。。。