【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::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順序編輯模式。
模式 | 含義 |
編輯控制元件 | 在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對話方塊提供可選擇檔案、字型、顏色等多種狀態的對話方塊類控制元件。
型別 | 說明 |
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::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::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::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::Nolcon | 不使用圖示 |
QMessageBox::Question | 使用Question圖示 |
QMessageBox::Information | 使用Information圖示 |
QMessageBox::Warning | 使用Warning圖示 |
QMessageBox::Critical | 使用Critical圖示 |