QT對話框中show和exec的區別
轉自:http://hi.baidu.com/wangjuns8/blog/item/24b382460dd1c1338694737d.html
QDialog的顯示有兩個函數show()和exec()。他們的區別在參考文檔上的解釋如下:
show():
顯示一個非模式對話框。控制權即刻返回給調用函數。
彈出窗口是否模式對話框,取決於modal屬性的值。
(原文:Shows the dialog as a modeless dialog. Control returns immediately to the calling code.
The dialog will be modal or modeless according to the value of the modal property. )
exec():
顯示一個模式對話框,並且鎖住程序直到用戶關閉該對話框為止。函數返回一個DialogCode結果。
在對話框彈出期間,用戶不可以切換同程序下的其它窗口,直到該對話框被關閉。
(原文:Shows the dialog as a modal dialog, blocking until the user closes it. The function returns a DialogCode result.
Users cannot interact with any other window in the same application until they close the dialog. )
先簡單說一下我對模式和非模式對話框的一點點理解:
模式對話框,就是在彈出窗口的時候,整個程序就被鎖定了,處於等待狀態,直到對話框被關閉。這時往往是需要對話框的返回值進行下面的操作。如:確認窗口(選擇“是”或“否”)。
非模式對話框,在調用彈出窗口之后,調用即刻返回,繼續下面的操作。這里只是一個調用指令的發出,不等待也不做任何處理。如:查找框。
從字面上看,show()即可以顯示非模式也可以顯示模式對話框(設置modal值)。當modal=true的時候是否跟exec()就一樣了呢?
經過測試,還是有區別的。
使用show(),雖然在對話框彈出的時候,程序的其它操作(按鈕、窗口切換等)都失效了;但是程序仍然在調用對話框之后,馬上返回繼續執行后面的代碼。這樣,你就不會得到窗口的返回值。以這個來看,show()只能算是“半模式”。
而使用exec(),在調用之后,程序就被鎖定在原地。等待窗口的關閉。
實際上,QDialog的show()函數來自其父類QWidget。而exec()則是自己的。
我最近特別喜歡繼承QWidget類來做彈出窗口,它的好處就是方便、靈活,既可以做為彈出窗口用也可以嵌入另外的頁面里(QDialog是不行的)。但問題是,QWidget沒有exec()函數。所以想彈出這樣模擬出來的模式對話框就不行了。
也查過一些資料,有說用while(true)循環的,有說用接收事件的,但都感覺不太好。
所以,目前還沒有找到比較好的解決辦法。
續:
上面遺留的問題經過查看QTE源代碼(沒有找到QT的)總算解決了。
我查看了QDialog類的exec()函數。發現里面同 樣調用了show(),只是在后面又調用了一句qApp->enter_loop()嵌套一個新的消息循環來阻塞當前事件的執行;然后在 hide()函數里調用了qApp->exit_loop()來退出當前的消息循環並繼續執行原事件。
到QT幫助里查了一下這兩個函數,解釋如下:
enter_loop():
這個函數被廢棄了。它仍然被保留下來是為了使舊的代碼能夠 繼續工作。我們強烈建議不要在新寫的代碼里使用它。這個函數直接介入主消息循環里(遞歸地)。除非你真的知道你在做什么,否則不要調用它。建議使 用:QApplication::eventLoop()->enterLoop()。
exit_loop():
同樣被廢棄了。建議使用:QApplication::eventLoop()->exitLoop()。
提醒:這兩個操作都會進入主消息循環,慎用!
那就按照建議的做吧,反正效果都是一樣的。修改原來的自定義窗口,在里面增加了兩個函數,分別實現打開和關閉窗口,封裝了eventLoop()的調用。代碼如下:
#include <qapplication.h>
#include <qeventloop.h>
/*模擬QDialog::exec(),以模式對話框方式顯示*/
void MyWidget::doExec()
{
this->show();
in_loop = TRUE;
//qApp->enter_loop();
QApplication::eventLoop()->enterLoop();
}
/*關閉窗口*/
void MyWidget::doClose()
{
if ( in_loop ) {
in_loop = FALSE;
//qApp->exit_loop();
QApplication::eventLoop()->exitLoop();
}
this->close();
}