show()和exec() (zz)

http://hi.baidu.com/wangjuns8/blog/item/24b382460dd1c1338694737d.html/cmtid/2fb3818c9b4f1ef5503d9202

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>

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();
}

發佈了0 篇原創文章 · 獲贊 1 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章