2.視窗部件-對話方塊QDialog

2022-08-30 18:03:16

1.模態和非模態

 

 

看程式碼 widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include<QDialog>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //指定父類別視窗 widget
    QDialog dialog(this);
    dialog.show();
    // 這樣執行會一閃而過,因為dialog 是函數中的一個變數,函數執行結束自動將變數回收.
    //為了不讓變數釋放,開闢一個記憶體空間
    QDialog *ql = new QDialog(this);
    //可以用setModal()函數預設設定的是Qt::ApplicationModal.
    dialog.setModal(true);
    ql->show();

    //還有方法 就是  呼叫 exec()函數讓程式阻塞.
     dialog.exec();
    //此刻執行會有對話彈出但是widget視窗並有出來,當關閉對話方塊後 widget 才會彈出來. 這種稱為模態對話方塊
    //只需呼叫exec() 就可變成模態對話方塊
    //模態對話方塊就是在這個視窗關閉前本應用程式不能再與其他視窗進行互動.
    //非模態對話方塊即使開啟對話方塊本不會影響本應用於其他視窗互動.

}

Widget::~Widget()
{
    delete ui;
}

 

執行程式後可以看到,生成的對話方塊是模態的。但是,它與用exec()函數時的效果是不一樣的,因為現在的MyWidget視窗也顯示出來了。這是因為呼叫完show()函數後會立即將控制權交給呼叫者,程式可以繼續往下執行。而呼叫exec()函數卻不同,只有當對話方塊被關閉時才會返回。與setModal()函數相似的還有一個setWindow-Modality()函數,它有一個引數來設定模態對話方塊要阻塞的視窗型別,可以是Qt∶∶NonModal(不阻塞任何視窗,就是非模態)、Qt∶∶∶WindowModal(阻塞它的父視窗、所有祖先視窗以及它們的子視窗)或Qt∶∶ApplicationModal(阻塞整個應用程式的所有視窗)。而 setModal()函數預設設定的是Qt∶∶ApplicationModal。

2.多視窗切換  訊號和槽

     Qt中使用訊號和槽機制來完成物件之間的協同操作。簡單來說,訊號和槽都是函數,比如單擊視窗上的一個按鈕後想要彈出一個對話方塊,那麼可以將這個按鈕的單擊訊號和自定義的槽關聯起來,在這個槽中建立一個對話方塊並且顯示它。這樣,單擊這個按鈕時就會發射訊號,進而執行槽來顯示一個對話方塊。下面來看一個例子。

雙擊widget.ui檔案,在設計模式中往介面新增一個Label和一個Push Button,在屬性欄中將Push Button的objectName 改為showChildButton,然後更改Label的顯示文字為「我是主介面!」,更改按鈕的顯示文字為「顯示子視窗」。然後回到編輯模式開啟widget.h檔案,

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

public slots:
    void showChildDialog();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include<QDialog>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(ui->showChildButton,&QPushButton::clicked,[=](){
        showChildDialog();
    });
}


Widget::~Widget()
{
    delete ui;
}

void Widget::showChildDialog()
{
   QDialog *dialog = new QDialog(this);
   dialog->show();
}

以上是手動連結槽   在編寫程式碼的一般會用 手動 connect

還有一種自動連結槽

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
public slots:
    void on_showChildButton_clicked();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include<QDialog>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_showChildButton_clicked()
{
   QDialog *dialog = new QDialog(this);
   dialog->show();
}

執行程式和使用connect 函數一樣.

1  on_showChildButton_clicked 這個名字很關鍵. pushButton 的名字必須是 showChildButton 或者 在pushButton 的ObjectName 加上 on_objectName_clicked 這樣就能自動關聯上了.

2.可以用 setObjectName() 指定部件物件名字

自定義對話方塊

第一種方法 

第一步,新增自定義對話類框。依然在前面的專案中更改。首先向該專案中新增Qt 設計師介面類。介面模板選擇Dialog without Buttons,類名改為MyDialog。然後在設計模式中向視窗新增兩個Push Button,並且分別更改其顯示文字為「進入主介面」和「退出程式」。

第二步,設計訊號和槽。這裡使用設計器來實現「退出程式」按鈕的訊號和槽的關聯.如下圖 步驟2左鍵按住往下拖會彈出步驟三的介面 ,記得勾選最後點選ok 就關聯完畢了. 最後點選按鈕 7退出編輯.對應快捷鍵 F4, F3

 

 

 

 

 

 

 

 

 

 第二種方法:

現在設定「進入主介面」按鈕的訊號和槽的關聯。在該按鈕上右擊,在彈出的級聯選單中選擇「轉到槽」,然後在彈出的對話方塊中選擇 clicked()訊號,並單擊 OK 按鈕。這時便會進入程式碼編輯模式,並且定位到自動生成的 on_btExit_clicked()槽中。在其中新增程式碼∶

 

點選 步驟1 右鍵彈出對話方塊 選擇 轉到槽.程式碼會自動建立出來 如下 可以在裡面寫想要的邏輯

 

void MyDialog::on_btExit_clicked()
{
    qDebug()<<"on btExit_clicked.........";
    //這個 accept()函數是QDialog類中的一個槽,對於一個使用exec()函數實現的模態對話方塊,執行了這個槽就會隱藏這個模態對話方塊,並返回QDialog∶∶Accepted值,這
    //裡就是要使用這個值來判斷是哪個按鈕被按下了。與其對應的還有一個reject()槽,它可以返回一個QDialog∶∶Rejected值,前面的「退出程式」按鈕也可以關聯這個槽。
    
    
  // accept();
}

 

 

前面講述了兩種關聯訊號和槽的方法,第一種是直接在設計器中進行,這個更適合在設計器中的部件間進行。第二種方法是在設計器中直接進入相關訊號的槽,這個與前面講到的手寫函數是一樣的,它用的就是自動關聯,這樣也會在.h檔案中自動新增該槽的宣告,我們只須更改其實現程式碼就可以了。在以後的章節中,如果在設計器中新增的部件要使用訊號和槽,那麼都會使用第二種方法。

需要說明的是那個close()槽,它不一定使程式退出,只有當只剩下最後一個主介面了(就是沒有父視窗的介面),這時呼叫close()槽,程式才會退出;而其他情況下介面只是隱藏起來了,並沒有被銷燬。

 3.標準對話方塊

Qt提供了一些常用的對話方塊型別,它們全部繼承自QDialog類,並增加了自己的特色功能,比如獲取顏色、顯示特定資訊等。下面簡單講解這些對話方塊,可以在幫助索引中檢視Standard Dialogs關鍵字,也可以直接索引相關類的類名。

1. 顏色對話方塊

 

 

顏色對話方塊類QColorDialog提供了一個可以獲取指定顏色的對話方塊部件。下面建立一個顏色對話方塊。先在mywidget.cpp檔案中新增#include<QDebug>和#in-clude<QColorDialog>標頭檔案,然後從設計模式進入"顏色對話方塊"按鈕的clicked()單擊訊號槽。更改如void Widget::on_colorDialog_btn_clicked({

//顏色對話方塊中就是使用這種方法。其中,0表示顏色最淺,255表示顏色最深。在0~255與0.0~1.0之間可以通過簡單的數學運算來對應,其中0對應0.0,255對應1.0。在顏色對話方塊中還可以新增對 alpha 的設定,
    //就是在 getColor()函數中再使用最後一個引數∶
   // QColor color = QColorDialog::getColor(Qt::red,this,tr("1顏色對話方塊1"));
    //這裡使用了QColorDialog的靜態函數getColor()來獲取顏色,它的3個引數的作用分別是∶設定初始顏色、指定父視窗和設定對話方塊標題。
    //這裡的Qt∶red是Qt預定義的顏色物件,可以直接單擊該字串,然後按下Fl檢視其快捷幫助,或者在幫助索引中通過Qt∶∶GlobalColor關鍵字,
    //從而檢視到所有的預定義顏色列表。getColor()函數返回一個QColor型別資料。現在執行程式,然後單擊「顏色對話方塊」按鈕,如果不選擇顏色,
    //直接單擊OK,那麼輸出資訊應該是QColor(ARGB1,1,0,0),這裡的4個數值分別代表透明度(alpha)、紅色(red)、綠色(green)和藍色(blue)。
    //它們的數值都是從0.0~1.0,有效數位為6位。對於alpha來說,1.0表示完全不透明,這是預設值,而0.0 表示完全透明。對於三基色紅、綠、藍的數值,還可以使用0~255來表示,
    //顏色對話方塊中就是使用這種方法。其中,0表示顏色最淺,255表示顏色最深。在0~255與0.0~1.0之間可以通過簡單的數學運算來對應,其中0對應0.0,255對應1.0。在顏色對話方塊中還可以新增對 alpha 的設定,
    //就是在 getColor()函數中再使用最後一個引數∶
    //這裡的QColorDialog∶∶ShowAlphaChannel用來顯示alpha設定。可以執行程式檢視效果。
    QColor color = QColorDialog::getColor(Qt::red,this,tr("1顏色對話方塊1"),QColorDialog::ShowAlphaChannel);
    qDebug()<<"color:"<<color;

}

前面使用了QColorDialog類的靜態函數來直接顯示顏色對話方塊,好處是不用建立物件。但是如果想要更靈活的設定,則可以先建立物件,然後進行各項設定

void Widget::on_colorDialog_btn_clicked()
{
    
    QColorDialog dialog(Qt::red,this);                               //建立物件
    dialog.setOption(QColorDialog::ShowAlphaChannel);                //顯示alpha選項
    dialog.exec();                                                  //以模態形式執行對話方塊
    QColor color = dialog.currentColor();                           //獲取當前選擇的顏色
    qDebug()<<"color:"<<color;
}

2,檔案對話方塊

 

 

檔案對話方塊QFileDialog類提供了一個允許使用者選擇檔案或資料夾的對話方塊。繼續在mywidget.cpp中新增#include<QFileDialog>標頭檔案,然後從設計模式轉到"檔案對話方塊"按鈕的單擊訊號槽,並更改如下∶

void Widget::on_fileDialog_btn_clicked()
{
    QString filepath = QFileDialog::getOpenFileName(this,tr("file"),"D:",tr("圖片檔案(*png *jpg)"));
    qDebug()<<"fileName:"<<filepath;

    QStringList filepaths = QFileDialog::getOpenFileNames(this,tr("file"),"D:",tr("圖片檔案(*png *jpg)"));
            for (int i =filepaths.length();i<0;--i)
             {

                qDebug()<<"fileName:"<<filepaths[i];
             }
}

這裡使用了QFileDialog類中的getOpenFileName()函數來獲取選擇的檔名,這個函數會以模態方式執行一個檔案對話方塊。開啟後選擇一個檔案,單擊"開啟"按鈕後,這個函數便可以返回選擇的檔案的檔名。它的4個引數的作用分別是∶指定父視窗、設定對話方塊標題、指定預設開啟的目錄路徑和設定檔案型別過濾器。如果不指定檔案過濾器,則預設選擇所有型別的檔案。這裡指定了只選擇png和jpg兩種格式的圖片檔案(注意,程式碼中*png和*jpg之間需要一個空格),那麼在開啟的檔案對話方塊中只能顯示目錄下這兩種格式的檔案。還可以設定多個不同類別的過濾器,不同類別間使用兩個分號";;"隔開,例如,新增文字檔案型別∶

執行程式就可以同時選擇多個圖片檔案了,多個檔名存放在QStringList型別變數中。當然也可以不使用這些靜態函數,而是建立對話方塊物件來操作。除了上面的兩個函數外,QFileDialog類還提供了getSaveFileName()函數來實現儲存檔案對話方塊和檔案另存為對話方塊,還有 getExistingDirectory()函數來獲取一個已存在的資料夾路徑。因為它們的用法與上面的例子類似,這裡就不再舉

 

 

3.字型對話方塊

 

 

字型對話方塊QFontDialog類提供了一個可以選擇字型的對話方塊部件。先新增#include<QFontDialog>標頭檔案,然後轉到"字型對話方塊"按鈕的單擊訊號槽,更改如下∶

 

void Widget::on_fontDialog_btn_clicked()
{
   //ok 用於標記Ok按鈕
    bool ok =false;
    QFont font = QFontDialog::getFont(&ok,this);
    //如果單擊ok按鈕讓字型對話方塊使用新的字型
    //如果單擊cance按鈕,那麼輸出資訊
    if(ok)
    {
        ui->fileDialog_btn->setFont(font);

    }else
    {
        qDebug()<<"沒有選擇字型";
    }
}

這裡使用了QFileDialog類的getFont()靜態函數來獲取選擇的字型。這個函數的第一個引數是bool型別變數,用來存放按下的按鈕狀態,比如在開啟的字型對話方塊中單擊了OK按鈕,那麼這裡的 ok 就為 true,這樣來告訴程式已經選擇了字型。

 

4. 輸入對話方塊

 

 

 

 

 

輸入對話方塊QInputDialog類用來提供一個對話方塊,可以讓使用者輸入一個單一的數值或字串。先新增標頭檔案#include<QInputDialog>,然後進入"輸入對話方塊"按鈕的單擊訊號槽,更改如下∶

void Widget::on_inputDialog_btn_clicked()
{
     bool ok = false;

     QString str = QInputDialog::getText(this,tr("輸入字串對話方塊"),tr("請輸入使用者名稱:"),QLineEdit::Normal,tr("admin"),&ok);
     if(ok){
         qDebug()<<"string:"<<str;
     }
     //獲取整數
     int value1 = QInputDialog::getInt(this,tr("ddddd"),tr("ddd"),0,-199999,1000,1,&ok);
     if(ok) qDebug()<< "valuel:"<< value1;//獲取浮點數
     double value2 = QInputDialog::getDouble(this,tr("double"),tr("double"),0.00,-10000,10000,2,&ok);
     if(ok)qDebug()<<"value2:"<< value2;
     QStringList items;
     items << tr("條目1")<< tr("條目2");//獲取條目
     QString item = QInputDialog::getItem(this,tr("dddd"),tr("dddhhh"),items,0,true,&ok);
     if(ok)qDebug()<<"item:"<< item;

}

 

這裡一共建立了4個不同型別的輸入對話方塊。getText()函數可以提供一個可輸入字串的對話方塊,各引數的作用分別是∶指定父視窗、設定視窗標題、設定對話方塊中的標籤顯示文字、設定輸入字串的顯示模式(例如密碼可以顯示成小黑點,這裡選擇了顯示使用者輸入的實際內容)、設定輸入框中的預設字串和設定獲取按下按鈕資訊的bool變數;getInt()函數可以提供一個輸入整型數值的對話方塊,其中的引數100表示預設的數值是100,一1000表示可輸入的最小值是一1000,1000表示可輸入的最大值是1000,10表示使用箭頭按鈕,數值每次變化10;getDouble()函數可以提供一個輸入浮點型數值的對話方塊,其中的引數2表示小數的位數為2;getItemO函數提供一個可以輸入一個條目的對話方塊,需要先給它提供一些條目,例如這裡定義的QStringList型別的items,其中引數0表示預設顯示列表中的第0個條目(0就是第一個),引數true 設定條目是否可以被更改,true就是可以被更改。這裡使用了靜態函數,不過也可以自己定義物件,然後使用相關的函數進行設定。

5. 訊息對話方塊

 

 

 

 

 

 

訊息對話方塊QMessageBox類提供了一個模態的對話方塊來通知使用者一些資訊,或者向用戶提出一個問題並且獲取答案。先新增標頭檔案#include<QMessageBox>,然後轉到「訊息對話方塊」按鈕的單擊訊號槽中,新增如下程式碼∶

 


void Widget::on_messageDialog_btn_clicked()
{
//問題對話方塊
int queston = QMessageBox::question(this,tr("question??"),tr("Are you see qt?"),QMessageBox::Yes,QMessageBox::No);
if(queston == QMessageBox::Yes){
qDebug()<<"i have a question!";
}else{
qDebug()<<"not a question";
}
//提示資訊
int tips = QMessageBox::information(this,tr("wolaile ??"),tr("niyao laima dddd?"),QMessageBox::Ok);
if(tips == QMessageBox::Ok){
qDebug()<<"ok ok";
}
//警告資訊

int warn = QMessageBox::warning(this,tr("wolaile ??"),tr("niyao laima dddd?"),QMessageBox::Abort);
if(tips == QMessageBox::Abort){
qDebug()<<"abort abort abort";
}
//錯誤資訊
int error = QMessageBox::critical(this,tr("wolaile ??"),tr("niyao laima dddd?"),QMessageBox::YesAll);
if(tips == QMessageBox::YesAll){
qDebug()<<"yes yes yes";
}
//關於對話方塊
QMessageBox::about(this,tr("wolaile ??"),tr("niyao laima dddd?"));

}

這裡建立了4個不同型別的訊息對話方塊,分別擁有不同的圖示還有提示音(這個是作業系統設定的),幾個引數分別用於設定父視窗、標題列、顯示資訊和擁有的按鈕。這裡使用的按鈕都是QMessageBox類提供的標準按鈕。這幾個靜態函數的返回值就是那些標準按鈕,由QMessageBox∶StandardButton列舉型別指定,可以使用返回值來判斷使用者按下了哪個按鈕。about()函數沒有返回值,因為它預設只有一個按鈕,與其相似的還有一個 aboutQt()函數,用來顯示現在使用的 Qt 版本等資訊。如果想使用自定義的圖示和按鈕,那麼可以建立QMessageBox類物件,然後使用相關函數進行操作。

 

6.進度對話方塊

 

 

進度對話方塊QProgressDialog對一個耗時較長操作的進度提供了反饋。先新增#in-clude<QProgressDialog>標頭檔案,然後轉到"進度對話方塊"按鈕的單擊訊號槽,更改如下∶

 

void Widget::on_progressDialog_btn_clicked()
{
     progress = new QProgressDialog(tr("myProgress"),tr("cancel "),0,100,this); //建立
    progress->setWindowTitle(tr("progess"));	//設定視窗標題
    progress->setWindowModality(Qt::WindowModal);//對話方塊設定為模態
    progress->show();//顯示
    presss = 0;
    QTimer* timer = new QTimer();

    timer->start(500);
    timer->callOnTimeout([=](){
        qDebug()<<presss;
         this->progress->setValue(presss++);//設定進度條當前值
        QCoreApplication::processEvents(); //避免介面凍結
        if(progress->wasCanceled() || presss == 100){ //結束或者取消
            timer->stop();
            progress->cancel();
            }
    });

}

這裡首先建立了一個QProgressDialog類物件dialog,建構函式的引數分別用於設定對話方塊的標籤內容、取消按鈕的顯示文字、最小值、最大值和父視窗。然後將對話方塊設定為模態並進行顯示。for()迴圈語句模擬了檔案複製過程,setValue()函數使進度條向前推進為了避免長時間操作而使使用者介面凍結,必須不斷地呼叫QCoreApplica-tion類的靜態函數 processEvents(),可以將它放在for()迴圈語句中。使用QPro-gressDialog的 wasCanceled()函數來判斷使用者是否按下了「取消」按鈕,如果是,則中斷複製過程。這裡使用了模態對話方塊,QProgressDialog還可以實現非模態對話方塊,不過它需要定時器等的幫助。

 

7. 錯誤資訊對話方塊

 

 

 

錯誤資訊對話方塊QErrorMessage類提供了一個顯示錯誤資訊的對話方塊。首先開啟mywidget.h檔案新增類前置宣告∶

    QErrorMessage *errMessage;

 


 errMessage = new QErrorMessage(this);

void
Widget::on_progressDialog_btn_2_clicked() { errMessage->setWindowTitle(tr("error message!")); errMessage->showMessage(tr("you are error.....")); }

這裡首先新建了一個QErrorMessage對話方塊,並且呼叫它的showMessage()函數來顯示錯誤資訊,呼叫這個函數時對話方塊會以非模態的形式顯示出來。錯誤資訊對話方塊中預設有一個Show this message again核取方塊,可以選擇以後是否還要顯示相同錯誤資訊;為了這個核取方塊的功能有效,不能像前面幾個例子一樣在槽中直接建立對話方塊。

8.嚮導對話方塊

 

 

嚮導對話方塊QWizard類提供了一個設計嚮導介面的框架。對於嚮導對話方塊,讀者應該已經很熟悉了,比如安裝軟體時的嚮導和建立專案時的嚮導。QWizard之所以被稱為框架,是因為它具有設計一個嚮導全部的功能函數,可以使用它來實現想要的效果。Qt中包含了Trivial Wizard、License Wizard和Class Wizard 這3個範例程式,可以參考一下。

開啟mywidget.h檔案,然後新增標頭檔案#include<QWizard>,在MyWidget類的宣告中新增private型別函數宣告∶

    QWizardPage *createPage1();
    QWizardPage *createPage2();
    QWizardPage *createPage3();

.cpp 檔案

 


QWizardPage *Widget::createPage1()//嚮導1

{

   QWizardPage * page = new QWizardPage(this);

   page->setTitle("介紹");

   return page;

}

QWizardPage *Widget::createPage2()//嚮導2

{



   QWizardPage * page = new QWizardPage(this);

   page->setTitle("使用者選擇資訊");

   return page;

}

QWizardPage *Widget::createPage3()//嚮導3

{



   QWizardPage * page = new QWizardPage(this);

   page->setTitle("結束");

   return page;

}


void
Widget::on_progressDialog_btn_3_clicked() { QWizard wizard(this); wizard.setWindowTitle(tr("xiang dao dui hua kuang")); wizard.addPage(createPage1()); wizard.addPage(createPage2()); wizard.addPage(createPage3()); wizard.exec(); }

 

這裡新建了QWizard類物件,然後使用addPage()函數為其新增了3個頁面。這裡的引數是QWizardPage型別的指標,可以直接呼叫生成嚮導頁面函數。執行程式可以看到,嚮導頁面出現的順序和新增嚮導頁面的順序是一致的。

上面程式中的嚮導頁面是線性的,而且什麼內容也沒有新增。如果想設計自己的嚮導頁面,或新增圖片、自定義按鈕,或設定向導頁面順序等,那麼就需要再多瞭解一下QWizard類和QWizardPage類。