一、對話框簡介
開發桌面程序,總會需要使用對話框來實現短期任務或者簡潔的交互。在Qt中,提供了QDialog類來實現對話框。在QDialog和其子類中,對parent指針有額外的解釋:當parent為NULL時,對話框會作為一個頂層窗口,否則則會作為其父組件的子對話框(此時默認顯示在父組件的中心位置)。可以新建一個項目,在主窗口上添加一個push button,然后在相應的槽函數中添加如下代碼:
QDialog dlg; dlg.setWindowTitle("hello dialog !"); dlg.exec();
運行程序查看效果,然后將其修改為:
QDialog dlg(this); dlg.setWindowTitle("hello dialog !"); dlg.exec();
再運行程序,對比兩次的差別。
對話框分為模態對話框和非模態對話框兩種。模態對話框又分為應用級別的模態對話框和窗口級別的模態對話框。應用級別的模態對話框會阻塞同一應用下的所有窗口,當對話框出現時,用戶先要和對話框進行交互,直到對話框關閉才可以和訪問其他窗口;窗口級別的模態對話框只會阻塞與對話框相關聯的窗口,允許用戶與其他窗口進行交互;非模態對話框則與模態對話框相反,它不會阻塞用戶與任何窗口的交互。
Qt中,實現應用級別的模態對話框使用QDialog::exec()函數,例如我們上面寫的代碼,實現窗口級別的模態對話框使用QDialog::open()函數,實現非模態對話框使用QDialog::show()函數。將上面的代碼改為非模態對話框方式:
QDialog dlg; dlg.setWindowTitle("hello dialog !"); dlg.show();
運行發現對話框一閃而過,這是因為對話框創建在棧上,並且show()函數不會阻塞當前線程,對話框顯示后代碼會繼續向下執行,當執行完按鈕的槽函數后,超出對話框的作用域,對話框就被析構了。所以需要將對話框創建在堆上,如下:
QDialog* dlg = new QDialog; dlg->setWindowTitle("hello dialog !"); dlg->show();
創建在堆上就會涉及到釋放內存,我們可以指定對話框的parent 為主窗口
QDialog* dlg = new QDialog(this);
但是這樣如果主窗口不關閉,dialog就不會被銷毀,內存會一直被占用。並且QWidget類的parent只能是QWidget的指針,如果對話框不是顯示在界面類上怎么辦?針對這個問題,我們可以設置QDialog的WindowAttribute
QDialog* dlg = new QDialog; dlg->setWindowTitle("hello dialog !"); dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->show();
這樣當對話框關閉時會自動銷毀,QObject類還有一個deleteLater()函數,該函數會在事件循環結束后銷毀該對話框。
二、對話框數據傳遞
從模態對話框獲取數據:
QDialog dlg;
dlg.exec();
qDebug() << dlg.result();
運行后,不會獲取到結果,這是因為exec()(開啟一個事件循環)會阻塞當前線程,當關閉對話框exec()函數返回時才會執行下面的代碼,才可以獲取到數據。如果設置了WA_DeleteOnClose,那么當對話框關閉時就會被銷毀,就不能用這種方法獲取數據了。exec()函數有兩個返回值:QDialog::Accepted和QDialog::Rejected,通常我們會使用類似下面的代碼:
QDialog dlg; if (dlg.exec() == QDialog::Accepted) { //do something } else { //do something }
從非模態對話框獲取數據:
因為QDialog::show()函數不會阻塞線程,show()會立即返回,所以不能通過上面的方式來獲取數據,否則不等用戶輸入,已經執行了下面的代碼。我們可以使用信號和槽機制,來獲取數據。非模態對話框在關閉時可以調用QDialog::accept()或者QDialog::reject或者QDialog::done()函數,所以我們可以重寫QDialog::accept()函數,在這里發送信號。也可以重寫QDialog::closeEvent()函數來發送信號。然后在需要接受數據的窗口鏈接這個信號即可。
在QDialog子類中:
void UserAgeDialog::accept() { emit userAgeChanged(newAge); // newAge is an int QDialog::accept(); }
在mainwindow中:
void MainWindow::showUserAgeDialog() { UserAgeDialog *dialog = new UserAgeDialog(this); connect(dialog, &UserAgeDialog::userAgeChanged, this, &MainWindow::setUserAge); dialog->show(); }
void MainWindow::setUserAge(int age) { userAge = age; }
三、標准對話框
標准對話框就是Qt內置的對話框,它們都是繼承與QDialog類。打開幫助文檔找到QDialog類,

可以看到當前版本Qt所支持的內置對話框。
- QColorDialog:選擇顏色
- QErrorMessage:錯誤提示
- QFileDialog:選擇文件
- QFontDialog:選擇字體
- QinputDialog:允許用戶輸入一個值,並返回該值
- QMessageBox:模態對話框,用於提示信息,詢問問題等
- QProgressDialog:顯示操作過程
下面以QMessageBox為例,做個簡單介紹,QMessageBox用於顯示信息提示,我們通常會用到以下幾個靜態函數:
void about(QWidget * parent, const QString & title, const QString & text):顯示關於對話框。這是一個最簡單的對話框,其標題是 title,內容是 text,父窗口是 parent。對話框只有一個 OK 按鈕。void aboutQt(QWidget * parent, const QString & title = QString()):顯示關於 Qt 對話框。該對話框用於顯示有關 Qt 的信息。StandardButton critical(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):顯示嚴重錯誤對話框。這個對話框將顯示一個紅色的錯誤符號。我們可以通過 buttons 參數指明其顯示的按鈕。默認情況下只有一個 Ok 按鈕,我們可以使用StandardButtons類型指定多種按鈕。StandardButton information(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):QMessageBox::information()函數與QMessageBox::critical()類似,不同之處在於這個對話框提供一個普通信息圖標。StandardButton question(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = StandardButtons( Yes | No ), StandardButton defaultButton = NoButton):QMessageBox::question()函數與QMessageBox::critical()類似,不同之處在於這個對話框提供一個問號圖標,並且其顯示的按鈕是“是”和“否”兩個。StandardButton warning(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):QMessageBox::warning()函數與QMessageBox::critical()類似,不同之處在於這個對話框提供一個黃色嘆號圖標。
我們通過以下示例來了解一下QMessageBox的簡單使用:
if (QMessageBox::Yes == QMessageBox::question(this,"question","are you ok?",QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes)) { QMessageBox::information(this,"information","I'm glad to hear that"); } else { QMessageBox::information(this,"information","i'm sorry"); }
我們首先使用question來詢問一個問題,然后根據用戶點擊的按鈕不同作出相應的反應。QMessageBox類的static函數使用起來非常簡單方便,如果我們需要進行定制QMessageBox,則可以通過設置其屬性來實現。例如做一個詢問是否需要保存的對話框:
//首先創建一個QMessagBox QMessageBox box; //設置對話框標題 box.setText("The document has been modified"); //設置對話框信息 box.setInformativeText("Do you want to save your changes?"); //設置詳細信息,設置此屬性,對話框會有一個show details的按鈕,當點擊該按鈕時,顯示詳細信息 box.setDetailedText("this is detail information"); //設置對話框按鈕 box.setStandardButtons(QMessageBox::Save|QMessageBox::Discard|QMessageBox::Cancel); //設置對話框默認按鈕 box.setDefaultButton(QMessageBox::Save); //顯示對話框並接受返回值 int ret = box.exec(); //根據返回值不同,作出相應的操作 switch (ret) { case QMessageBox::Save: qDebug() << "save"; break; case QMessageBox::Discard: qDebug() << "discard"; break; case QMessageBox::Cancel: qDebug() << "cancel"; break; default: break; }
運行結果如下:

我這是在Mac下,如果是在windows下,那么Qt會自動將其設置為適應windows習慣的對話框。
