1. 程式人生 > >【Qt】Qt的GUI設計與製作(下篇:高階控制元件、Qt Designer、對話方塊)

【Qt】Qt的GUI設計與製作(下篇:高階控制元件、Qt Designer、對話方塊)

高階控制元件

Qt為了方便GUI的設計,不僅僅提供了QPushButton、QLabel這樣的單一控制元件,還提供了可以將多個控制元件功能合為一體的高階控制元件類。如:顯示日曆的QCalendarWidget類,還提供了將多個控制元件功能融為一體的控制元件。

QCalendarWidget

QCalendarWidget控制元件提供了將當前系統時間(年/月)日期顯示為日期格式的GUI。可以當前時間為基礎顯示日曆,也可以通過成員函式設定要顯示的年/月。

此空間可以通過滑鼠或者鍵盤移動日期,也可以利用成員函式selectdDate()獲取在控制元件上選擇的日期的資訊,還可以通過屬性引數minimunDate()和maximunDate()獲取當前月份的第一天和最後一天。

calendar=new QCalendarWidget(this);
calendar->setGridVisible(true);

宣告QCalendarWidget之後,可以獲取當前日期的年/月資訊,並提供GUI。同樣,也可以設定特定範圍內的起始日:

calendar->setMinimumDate(QDate(2000,1,1));
calendar->setMaximumDate(QDate(2020,1,1));

同樣還可以在QCalendarWidget重處理單擊資訊時間,選擇日期後,可以關聯訊號時間函式selectionChanged()與槽函式,還可以通過一下常量改變QCalendarWidget標題行的顯示風格。

QCalendarWidget標題顯示風格
常量 含義
QCalendarWidget::SingleLetterDayNames 1 顯示星期首字母
QCalendarWidget::ShortDayNames 2 顯示星期縮寫
QCalendarWidget::LongDayNames 3 顯示星期完整拼寫
QCalendarWidget::NoHorizontalHeader 0 不水平顯示標題行

 

使用Designer構建GUI

 

Designer簡介

使用Qt提供的Designer工具,可以不編寫程式碼也可以設計GUI。同時,使用Designer工具佈局的控制元件也實現訊號與槽的關聯。

這款工具的工作原理就是,首先轉換為使用Designer設計的GUI XML檔案,再利用qmake轉換為程式碼,然後進行編譯。

編輯模式

Qt Designer提供了空間編輯模式、訊號與槽編輯模式、夥伴編輯模式和Tab順序編輯模式。

Qt編輯模式
模式 含義
編輯控制元件 在GUI窗體上新增控制元件和介面佈局,編輯控制元件屬性
編輯訊號與槽 已佈局的控制元件和訊號與槽相連線
編輯夥伴 通過包含到標籤控制元件的快捷鍵分配鍵盤焦點
編輯Tab順序 不同Tab按順序移動控制元件的視窗焦點

佈局管理功能

Designer設計GUI時,不僅僅可以利用絕對座標通過滑鼠佈局控制元件,也可以使用佈局管理器。下圖提供了兩種方式:

預覽功能

Qt Designer支援預覽功能,一檢視設計的GUI的效果。在使用Designer設計GUI的過程中,可以通過此功能快捷鍵預覽GUI。還可以使用快捷鍵Ctrl+R進行預覽。

使用容器類控制元件

使用Designer時,可以使用Qt提供的容器類控制元件。例如:在組合框中可以設計包含QCheckBox控制元件的GUI。下圖提供了兩種方式:

設計主視窗

Designer不僅僅可以用單一控制元件設計GUI,還可以提供設計多個GUI的主視窗(Main Window)。可以向主視窗新增選單,藿香選單新增特定控制元件。

 

訊號與槽的使用

這裡使用Designer來設計訊號與槽的使用,一共提供兩種方法。下面以一個簡單的例子分別說明這兩個方法的內容:

程式定義

在定義每一個控制元件的時候,視窗右下會對這個控制元件進行設定。比如:控制元件名、大小、位置等等。

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

public slots:                                           //槽函式
    void slider_valueChanged(int value);

private:
    Ui::Widget *ui;                                //連線Designer建立的GUI的橋樑
};

#endif // WIDGET_H

當我們在Designer中定義一個控制元件,那麼在程式中使用“ui->”就能直接引用該物件。並且該物件不需要在程式中進行定義宣告,ui會自動生成這一切!

也就是說,在程式中使用Designer中定義的控制元件,都必須使用“ui->”來進行引用。

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(ui->horizontalSlider,SIGNAL(valueChanged(int)),this,SLOT(slider_valueChanged(int)));        //槽函式
}

void Widget::slider_valueChanged(int value){                    //定義槽函式
    ui->spinBox->setValue(value);
}

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

這裡需要注意一點:connect()的槽函式必須宣告在“ui->setupUi(this)”之後,不然會出現錯誤!

Designer定義

除了使用程式定義之外,也可以使用Designer帶有的工具來進行訊號與槽的連線。

單擊Qt Creator的“編輯(Edit)”選單,在彈出的子選單裡面點選“編輯訊號/槽(Edit signals/slots)”,此時,當滑鼠移動到某個控制元件上時,該控制元件的顏色變成紅色。然後單擊訊號控制元件,拖動滑鼠到槽控制元件:

就可以選擇訊號函式和對應的槽函數了。

這種方式雖然避免了程式的編寫,但是槽函式沒有什麼選擇權,都是比較簡單。沒有太多的可能性。除非是非常簡單的功能,否則很有可能時實現不了的。

如果想要退出該模式,單擊Qt Creator的“編輯(Edit)”選單,在彈出的子選單裡面點選“編輯widget(Edit widgets)”。

 

對話方塊

對話方塊提供了允許使用者輸入值的GUI。例如,可以在基於主視窗或單視窗的應用程式上建立新對話方塊並輸入值。

普通對話方塊

Qt對話方塊提供可選擇檔案、字型、顏色等多種狀態的對話方塊類控制元件。

Qt對話方塊控制元件型別
型別 說明
QInputDialog 使用者可以輸入值的對話方塊
QColorDialog 可以選擇指定顏色的對話方塊
QFileDialog 提供選擇檔案或目錄的GUI的對話方塊
QFontDialog 可以選擇字型的對話方塊
QMessageBox 模式對話方塊,通過主視窗傳送使用者所選專案的返回值(如:確定、取消)
QProcessDialog 顯示百分比進度的對話方塊

QInputDialog

QInputDialog提供接收使用者輸入值的對話方塊。輸入值可以是整數、實數或者QString的字串。

bool retValue;
int i = QInputDialog::getInt(this,tr("input"),tr("number"),0,0,100,1,&retValue);            //A

if(retValue){
        qDebug("true. %d",i);
}else{
        qDebug("false.");
}

只需要這一段程式碼,除了標頭檔案之外,其他什麼都不需要新增。也就是,不需要new,就能生成一個對話方塊。

解釋一下A行:

getInt()表示接受整數值的對話方塊。引數:指定父類、窗體的標題、輸入值控制元件的標籤、預設設定值、輸入範圍最小值、輸入範圍最大值、對話方塊的的STEP、檢視是否點選了對話方塊的“OK”或者“Cancel”。

為什麼要設定最後一項呢?

如果使用者取消了,但是i仍然能接收到一個數字(預設設定值)。

而對於getDouble()就比較類似,不贅述了。

講一下getItem()函式,是接受下拉框選擇的值:

QStringList items;                                                //字串列表
items<<tr("Spring")<<tr("Summer")<<tr("Fall")<<tr("Winter");

bool ok;
QString item = QInputDialog::getItem(this,tr("Input"),tr("Season"),items,0,false,&ok);

if(ok&&!item.isEmpty()){
        qDebug()<<item;
}

這段程式的執行結果為:

再講一下getText()函式,是接收字串的值:

bool ok;
QString text = QInputDialog::getText(this,tr("Input"),tr("Text"),QLineEdit::Normal,tr("Username"),&ok);

if(ok&&!text.isEmpty()){
        qDebug()<<text;
}

這段程式的執行結果為:

QColorDialog

QColorDialog是使用者選擇顏色的對話方塊。

QColor color;
color = QColorDialog::getColor(Qt::blue,this,"Color:",QColorDialog::DontUseNativeDialog);

if(color.isValid()){
        qDebug()<<color.name();
}

這段程式的執行結果為:

解釋一下getColor()的各個引數:QColorDialog的預設顏色、指定父類、對話方塊標題欄,指定option值。其中可以指定的option的值有:

QColorDialog各常量
常量 說明
QColorDialog::ShowAlphaChannel 1 可以選擇alpha值
QColorDialog::NoButtons 2 不顯示OK和CANCEL按鈕

QFontDialog

QFontDialog是使用者可以選擇字型的對話方塊。

bool ok;
QFont font = QFontDialog::getFont(&ok,QFont("宋體"),this);

if(ok){
        qDebug()<<font.key();
}

這段程式的執行結果為:

QFileDialog

QFileDialog是提供使用者可以進行開啟、儲存、選擇目錄等檔案處理的對話方塊。

可以使用成員函式getOpenFileName()選擇原始檔案;使用成員函式getOpenFileNames()選擇多個目錄內的多個檔案;使用成員函式getExistingDirectory()選擇目錄;使用成員函式getSaveFileName()指定要儲存的檔案的對話方塊功能。

getExistingDirectory()選擇目錄

QFileDialog::Options options;
options = QFileDialog::DontResolveSymlinks|QFileDialog::ShowDirsOnly;
options |= QFileDialog::DontUseNativeDialog;

QString directory = QFileDialog::getExistingDirectory(this,tr("File:"),"/home",options);
qDebug()<<directory;

這段程式執行的結果為:

這裡講一下QFileDialog的options常量值:

QFileDialog各常量值
常量 說明
QFileDialog::ShowDirsOnly 1 只顯示目錄
QFileDialog::DontResolveSymlinks 2 不顯示符號連結
QFileDialog::DontConfirmOverwrite 3 覆寫現存檔案時,不顯示警告資訊
QFileDialog::DontUseNativeDialog 10 不使用系統預設檔案對話方塊
QFileDialog::ReadOnly 20 使用只讀模式檔案對話方塊
QFileDialog::HideNameFilterDetails 40 使用過濾器隱藏檔案

getOpenFileName()選擇單個檔案

QFileDialog::Options options;
options |= QFileDialog::DontUseNativeDialog;

QString selectedFilter;
QString fileName = QFileDialog::getOpenFileName(this,tr("File"),"/",tr("All Files (*);;Picture Files (*.jpg);;Text Files (*.txt)"),&selectedFilter,options);

qDebug()<<fileName;
qDebug()<<selectedFilter;

這段程式的執行結果為:

解釋一下getOpenFileName()的各個引數:指定父類、對話方塊的標題、對話方塊起始的目錄、可選擇的檔案型別、使用者選擇的檔案型別、options常量值。

注意一下:在編輯可選擇的檔案型別時,每兩個不同的檔案型別之間用“;;”隔開,是兩個分號隔開

getSaveFileName()指定要儲存的檔案

QFileDialog::Options options;
options |= QFileDialog::DontUseNativeDialog;

QString selectedFilter;
QString fileName = QFileDialog::getSaveFileName(this,tr("File:"),".txt",tr("ALL Files (*);;Text Files (*.txt)"),&selectedFilter,options);

qDebug()<<fileName;
qDebug()<<selectedFilter;

這段程式執行的結果為:

QMessageBox

QMessageBox是提供模式對話方塊的類。向用戶顯示資訊,並能接收以下按鈕輸入。

QMessageBox各按鈕常量值
常量 說明
QMessageBox::Ok OK按鈕
QMessageBox::Open 開啟檔案按鈕
QMessageBox::Save 儲存按鈕
QMessageBox::Cancel 取消按鈕
QMessageBox::Close 關閉按鈕
QMessageBox::Discard 不儲存且放棄按鈕
QMessageBox::Apply 請求按鈕
QMessageBox::Reset 重置按鈕
QMessageBox::RestoreDefaults 重新儲存按鈕
QMessageBox::Help 幫助按鈕
QMessageBox::SaveAll 全部儲存按鈕
QMessageBox::Yes Yes按鈕
QMessageBox::YesToAll 全部執行Yes按鈕
QMessageBox::No No按鈕
QMessageBox::NoToAll 全部執行No按鈕
QMessageBox::Abort 停止按鈕
QMessageBox::Retry 重試按鈕
QMessageBox::Ignore 忽略按鈕
QMessageBox::NoButton 無效按鈕

critical()訊息框

QMessageBox::StandardButton reply;
reply = QMessageBox::critical(this,tr("Message"),"There is no a fisk.",QMessageBox::Abort|QMessageBox::Retry|QMessageBox::Ignore);

if(reply==QMessageBox::Abort){
        qDebug("Abort");
}else if(reply==QMessageBox::Ignore){
        qDebug("Ignore");
}else{
        qDebug("Retry");
}

這段程式的執行結果為:

information()訊息框

QMessageBox::StandardButton reply;
reply = QMessageBox::information(this,tr("Message"),"There is no a fisk.");

if(reply==QMessageBox::Ok){
        qDebug("Ok");
}

這段程式的執行結果為:

由於information()訊息框只是傳遞訊息,預設有一個OK按鈕,就無需手動添加了。

Question()訊息框

QMessageBox::StandardButton reply;
reply = QMessageBox::question(this,tr("Message"),"Do you save this file?",QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel);

if(reply==QMessageBox::Yes){
        qDebug("Yes");
}else if(reply==QMessageBox::No){
        qDebug("No");
}else{
        qDebug("Cancel");
}

這段程式的執行結果為:

warning()對話方塊

QMessageBox::StandardButton reply;
reply = QMessageBox::warning(this,tr("Message"),"There is no a fisk.",QMessageBox::Abort|QMessageBox::Retry|QMessageBox::Ignore);

if(reply==QMessageBox::Abort){
        qDebug("Abort");
}else if(reply==QMessageBox::Ignore){
        qDebug("Ignore");
}else{
        qDebug("Retry");
}

這段程式的執行結果為:

當然,上面的都是使用定義好的按鈕,還有一種方式,可以自己定義按鈕的顯示內容。

QMessageBox msgBox(QMessageBox::Warning,tr("Message"),"是否儲存?",0,this);
msgBox.addButton(tr("是"),QMessageBox::AcceptRole);
msgBox.addButton(tr("否"),QMessageBox::RejectRole);

if(msgBox.exec()==QMessageBox::AcceptRole){
        qDebug("儲存");
}else{
        qDebug("不儲存");
}

這段程式的執行結果為:

儘管可以自定義按鈕的顯示內容,但是QMessageBox上面的圖示還是隻能是以下四種:

QMessageBox圖示常量
常量 說明
QMessageBox::Nolcon 不使用圖示
QMessageBox::Question 使用Question圖示
QMessageBox::Information 使用Information圖示
QMessageBox::Warning 使用Warning圖示
QMessageBox::Critical 使用Critical圖示