Qt學習五 - 對話框


一、對話框簡介

開發桌面程序,總會需要使用對話框來實現短期任務或者簡潔的交互。在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習慣的對話框。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM