QT中的模态对话框及非模态对话框
模態(tài)對話框(Modal Dialog)與非模態(tài)對話框(Modeless Dialog)的概念不是Qt所獨有的,在各種不同的平臺下都存在。又有叫法是稱為模式對話框,無模式對話框等。所謂模態(tài)對話框就是在其沒有被關(guān)閉之前,用戶不能與同一個應用程序的其他窗口進行交互,直到該對話框關(guān)閉。對于非模態(tài)對話框,當被打開時,用戶既可選擇和該對話框進行交互,也可以選擇同應用程序的其他窗口交互。
在Qt中,顯示一個對話框一般有兩種方式,一種是使用exec()方法,它總是以模態(tài)來顯示對話框;另一種是使用show()方法,它使得對話框既可以模態(tài)顯示,也可以非模態(tài)顯示,決定它是模態(tài)還是非模態(tài)的是對話框的modal屬性。
在Qt中,Qt的模態(tài)與非模態(tài)對話框選擇是通過其屬性modal來確定的。我們來看看modal屬性,其定義如下:
modal : bool默認情況下,對話框的該屬性值是false,這時通過show()方法顯示的對話框就是非模態(tài)的。而如果將該屬性值設置為true,就設置成了模態(tài)對話框,其作用于把QWidget::windowModality屬性設置為Qt::ApplicationModal。
而使用exec()方法顯示對話框的話,將忽略modal屬性值的設置并把對話框設置為模態(tài)對話框。
一般使用setModal()方法來設置對話框的modal屬性。
我們總結(jié)一下設置對話框為模態(tài)的方法。
◆ 如果要設置為模態(tài)對話框,最簡單的就是使用exec()方法,示例代碼如下:
MyDialog myDlg;????myDlg.exec();也可以使用show()方法,示例代碼如下:
MyDialog myDlg;????myDlg.setModal(true);????myDlg.show();
◆??如果要設置為非模態(tài)對話框,必須使用show()方法,示例代碼如下:
MyDialog myDlg;????myDlg.setModal(false);
//或者
myDlg.setModal();
myDlg.show();
再次強調(diào),目前有的朋友對于模態(tài)對話框和非模態(tài)對話框的認識有誤解,認為使用show()方法顯示的就是非模態(tài)對話框,這是不正確的。
小貼士:有時候,我們需要一個對話框以非模態(tài)的形式顯示,但又需要它總在所有窗口的最前面,這時可以通過如下代碼設置:
MyDialog myDlg;????myDlg.setModal(false);
//或者
myDlg.setModal();????myDlg.show();
//關(guān)鍵是下面這行
myDlg.setWindowFlags(Qt::WindowStaysOnTopHint);
在Qt中創(chuàng)建模態(tài)對話框,主要用到了QDialog的exec函數(shù):
SonDialog dlg(this);
int res = dlg.exec();
if (res == QDialog::Accepted)
{
QMessageBox::information(this, “INFORMATION”, “You clicked OK button!”);
}
if (res == QDialog::Rejected)
{
QMessageBox::information(this, “INFORMATION”, “You clicked CANCEL button!”);
}
正如上面代碼所顯示的,可以通過exec函數(shù)的返回值來判斷用戶點擊了哪個按鈕使得模態(tài)對話框退出的,這可以使得我們能夠根據(jù)用戶的不同行為在退出模態(tài)對話框之后采取不同的處理方法。
既然new了,如果不delete,那么內(nèi)存不就存在了泄露的問題了嗎?確實如此!所以,我們希望該Qt窗口在退出時自動能夠delete掉自己,因此,我們在SonDialog的構(gòu)造函數(shù)里,添加這樣的一句代碼:
setAttribute (Qt::WA_DeleteOnClose);
這樣,我們的SonDialog就能夠在它退出時自動的delete掉自己了,不會再造成內(nèi)存泄漏問題
?
Qt中存在“窗口”與“部件”的區(qū)分,但“窗口”的概念太過淺顯,以至于可以忽略不談。但有時候還是多少有些了解為好。
很多書上說,Qt中吧沒有嵌入到其他部件中的部件成為“窗口”,而這種“窗口”都包含有邊框和標題欄。“窗口”就是沒有父窗口(或部件)的部件,又稱為頂級部件。但在實際開發(fā)過Qt程序的工程師看來,這種說法有點欠佳。“窗口是沒有嵌入到其他部件的部件“這個好理解,但是“窗口”就是沒有父部件的部件?QDialog為窗口是毋庸置疑的吧,但是在使用對話框時為其指定父窗口也是在正常不過了。例如,當我點擊主窗口某個按鈕時彈出個提示對話框:
QDialog?dlg(this);
dlg.exec();
彈出的Dialog一樣具有邊框和標題欄,難道這種具有父部件的對話框就是不是窗口了?很多人難以接受吧! 所以,一個QWidget是窗體還是窗體上的控件和是否有父類無關(guān),只與窗口標記類型有關(guān),也只有窗口flag才能直接說明此部件是否為窗口!設置或修改部件類型:setWindowFlags(Qt::Window)
但是也無需懷疑很多書本的可靠性,其實書上說的也沒錯,只是不夠深入。例如:
QPushButton?*?pPushBtn?=?new?QPushButton(this);
//當沒有父類時,構(gòu)造函數(shù)就會加上Qt::Window標記
QPushButton * pPushBtn = new QPushButton;
因為,當沒有指定父窗口(部件)時都是默認設置了Qt::Window標記的。再如:
//不管有無父類都為窗體,因為向QWidget傳參數(shù)時傳遞了Qt::Dialog標記.
QDialog * dlg = new QDialog(this);
因此,QDialog是個獨特的部件,無論有無指定父部件,其生來就是Window!
?
總而言之:所以使QWidget變成Window(窗體)只能使用setWindowFlags(Qt::Window); !!!在使用Qt是一般不考慮窗口的概念,較多情況下都直接使用QWidget就行了,對于自定義部件也是如此。對于之前做過VC的選手可能習慣了使用CDialog,但在Qt中QDialog卻沒那么受待見,熟練使用QWidget才是王道。
?
對于?QDialog?的模態(tài)及非模態(tài)是直接可以實現(xiàn)的,很多課本中都會提到,此處總結(jié)下。
?
模態(tài)QDialog
方式一:
QDialog?dlg(this);
dlg.exec();
方式二:
QDialog?*pDlg=new?QDialog(this);
pDlg->setModal(true);
pDlg->show();
非模態(tài)QDialog
QDialog?*pDlg=new?QDialog(this);
pDlg->show();
?
QDialog實現(xiàn)模態(tài)非模態(tài)很簡單,但是對于QWidget有點迷茫,QWidget中沒有exec(),也沒有setModal()方式,但是想想看,QWidget作為QDialog的基類,而且QWidget作為“窗口”使用也是在平常不過了,所以會意識到QWidget中是否存在一個相對exec()或setModal()更基本的操作來實現(xiàn)模態(tài)和非模態(tài)呢?就這樣,我找到了setWindowModality(),此函數(shù)就是用來設置QWidget運行時的程序阻塞方式的,參數(shù)解釋如下:
Qt::NonModal?不阻塞
Qt::WindowModal?阻塞父窗口,所有祖先窗口及其子窗口
Qt::ApplicationModal?阻塞整個應用程序
?
看來,setModal()也就是使用setWindowModality()設置Qt::ApplicationModal參數(shù)也實現(xiàn)的模態(tài)。
?
如此,要實現(xiàn)QWidget的模態(tài)和非模態(tài),只要調(diào)用setWindowModality()設置阻塞類型就好了:
QWidget *pWid = new QWidget(this); pWid->setWindowModality(Qt::ApplicationModal); //pWid->setAttribute(Qt::WA_ShowModal, true); pWid->show();但是運行發(fā)現(xiàn)并未實現(xiàn)模態(tài)效果。這里需要注意,當希望使用setWindowModality()將QWidget設置為模態(tài)時應該保證QWidget父部件為0,這里修改QWidget *pWid = new QWidget(this);為QWidget *pWid = new QWidget(NULL);在運行就好了。
?
此外,通過setWindowModality()設置模態(tài)窗口并不是唯一方式,直接設置部件(或窗口)屬性也可以:
pWid->setAttribute(Qt::WA_ShowModal,?true)
---------------
還有很多地方需要注意,當創(chuàng)建QDialog后使用setWindowFlags(Qt::FramelessWindowHint);去掉標題欄時此對話框不再阻塞父窗口,如果需要實現(xiàn)阻塞效果可再次指定Qt::Dialog,即使用:
setWindowFlags(Qt::Dialog?|?Qt::FramelessWindowHint); //這樣就會阻塞父窗口了!
但是,這樣會影響對話框的半透明(或透明)顯示。使用Qt::Dialog之前半透明顯示正常:
?
使用之后卻死活不行了:
?
-- 不知道如何是好!?
--------------
總而言之
是否是模態(tài)和QDialog 和QWidget都可以模態(tài)和非模態(tài).exec(), show()?等函數(shù)無直接關(guān)系,只和窗口屬性有關(guān),使用以下兩種方式都行:
setAttribute(Qt::WA_ShowModal, true);//屬性設置
setWindowModality(Qt::ApplicationModal);//設置阻塞類型
-----------------
QDialog中的成員函數(shù)setModal(true)及exec()之所以是模態(tài)是因為他先設置了窗口屬性:setAttribute()再show()的
模態(tài)對話框:指該對話框關(guān)閉之前不可以對其他窗口進行操作,只有等該對話框關(guān)閉之后才可以操作其他窗口。
非模態(tài)對話框:該對話框激活的情況下也可以對其他窗口進行操作。
模態(tài)對話框:
Qdialog dlg;
dlg.show();
執(zhí)行上面的代碼,我們會發(fā)現(xiàn)窗口一閃而過,其原因是因為dlg被申明為一個局部變量,當用完之后就自動銷毀,所以窗口show完之后立馬就被釋放。為了不讓它一閃而過,使用
dlg.exec();//阻塞
這個語句起到阻塞程序的作用,當執(zhí)行到這里的時候停住了,這樣也不能對其他窗口進行操作,所以
Qdialog dlg;
dlg.exec();
就是模態(tài)對話框的寫法。
非模態(tài)對話框:
Qdialog *dlg=new Qdialog;
dlg->show();
dlg->setAttribute(Qt::WA_DelecteOnClose);
執(zhí)行上面程序彈出窗口不會一閃而過,因為new創(chuàng)建在堆上,不會自動銷毀,需要手動delete。dlg->setAttribute(Qt::WA_DelecteOnClose)的作用是當窗口關(guān)閉時,對話框釋放。
?
模態(tài)對話框:非阻塞
?
//方法1 TestDialog childWindow ; childWindow.setModal(false); //childWindow.show();//不可行 childWindow.exec();//可行 //方法2 TestDialog * childWindow = new TestDialog(); childWindow->setModal(false); childWindow->show();在子窗口初始化中加入
setAttribute?(Qt::WA_DeleteOnClose);
防止內(nèi)存泄漏。
?
非模態(tài)對話框:阻塞
?
//方法1
?
TestDialog * childWindow = new TestDialog(); childWindow->setModal(true); childWindow->show();//方法2
?
TestDialog* childWindow = new TestDialog(); childWindow->setWindowModality(Qt::WindowModal); childWindow->show();qDialog的setmodal,對話框模態(tài)、非模態(tài)
對話框模態(tài),關(guān)閉當前對話框前,無法操作其他窗口
非模態(tài),當前對話框打開同時,也可以操作其他對話框
模態(tài)在對話框創(chuàng)建時設定好后,程序運行過程中無法切換!(如:對話框A當前為非模態(tài),彈出后,設置為模態(tài),不起作用)
?
1.如果使用exec()默認為模態(tài)的。如果用show()需要設置setModel(true)才是模態(tài)的。
?
方法1:模態(tài)窗口
A為窗口類,? 父類窗口為B
A *dlg = new A(this,pB)(可確保A顯示在B之上)
dlg->exe();
注意:此時使用setModal無效果
?
方法2:
A *dlg = new A(this,pB)(可確保A顯示在B之上)
dlg-.setModel(true);
dlg->show();
?
2、close()會銷毀對象嘛。只有當設置了 setAttribute(WA:closeOnDelelte)是才會刪除,如果這個標志沒有設置,其作用和hide(),setvisible(false)一樣,只會隱藏改對象。
?
A為窗口類,? 父類窗口為B
A *dlg = new A(this,pB)(可確保A顯示在B之上)
dlg->setAttribute(WA:closeOnDelelte);
dlg->show;
注意,此時需要使用close();否則dlg指針未被管理。
?
3、QWidget的模態(tài)和非模態(tài);
?
4、阻塞?
QDialog模態(tài)對話框與非模態(tài)對話框 范例
//模態(tài)1
MyWidget*w = new MyWidget; //派生于QWidget
w->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
w->setAttribute(Qt::WA_ShowModal, true);
w->setAttribute(Qt::WA_DeleteOnClose, true);
w->show();
?
//模態(tài)2
?
MyDialog _dialog; //派生于QDialog
int ret = _dialog.exec();
if (ret == QDialog::Accepted)
{
}
?
//模態(tài)附加
?
void on__btnSave_clicked()
{
this->accept();
this->close();
}
?
if (res == QDialog::Accepted)
?
//非模態(tài)
?
MyDialog* _pMyDialog = new MyDialog ;
_pMyDialog->setAttribute(Qt::WA_DeleteOnClose);
_pMyDialog->setModal(false);
_pMyDialog->show();
?
?
?
總結(jié)
以上是生活随笔為你收集整理的QT中的模态对话框及非模态对话框的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springCloud - 第12篇 -
- 下一篇: QT5完成一个数据实时显示控制的Demo