對話框是GUI程式和使用者進行簡短互動的頂層視窗,所謂頂層視窗即始終在主視窗之上顯示。QDialog是Qt所有類型的對話框視窗的基類,它繼承于QWidget,是一種容器類型元件。
QWidget是所有視窗類的抽象,它也可以生成對話框,但是對話框是常見的視窗元件,若每次要使用對話框,都利用QWidget來生成并設定相關參數,顯然十分繁瑣。是以Qt為我們封裝了另外一個子類QDialog,專門用于生成對話框。
1. 模态和非模态對話框
對話框歸為兩大類,即模态對話框于非模态對話框。
模态對話框(QDialog::exec())
阻塞型的對話框,顯示後無法與父視窗進行互動。如word文檔中修改源檔案内容後直接關閉視窗彈出的對話框:
非模态對話框(QDialog::show())
非阻塞型的對話框,顯示後還可以與父視窗進行互動。如word文檔的替換操作:
模态對話框:
(1) 定義一個主視窗,視窗内有一個按鈕:
//Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QApplication>
#include <QWidget>
#include <QPushButton>
#include <QDebug>
class Widget : public QWidget
{
Q_OBJECT //表要類要使用信号與槽機制
protected:
QPushButton Btn; //按鈕
protected slots:
void Btn_Clicked(); //槽,用于響應按鈕按下操作
public:
Widget(QWidget *parent = ); //parent預設參數為0,表預設是容器類父視窗
~Widget();
};
#endif // WIDGET_H
//Widget.cpp
#include "Widget.h"
#include "Dialog.h"
//Widget的構造函數,Btn初始化為其Widget的功能類字子元件
Widget::Widget(QWidget *parent) : QWidget(parent), Btn(this)
{
Btn.resize(, );
Btn.move(, );
Btn.setText("btn");
resize(, );
setWindowTitle("hello");
connect(&Btn, SIGNAL(clicked()), this, SLOT(Btn_Clicked()));
}
Widget::~Widget()
{
}
//Widget内按鈕的響應槽,該按鈕按下後Winget會彈出對話框(Dialog)
void Widget::Btn_Clicked()
{
qDebug() << "Btn_Clicked()";
Dialog d(this); //Dialog是對話框類,見下
int ret = d.exec(); //exec()表明d是個模态對話框,使用者不操作該對話框,會阻塞于此。
//exec()傳回對話框的運作結果
if (ret == Dialog::Accepted)
{
qDebug() << "Accepted";
}
else if (ret == Dialog::Rejected)
{
qDebug() << "Rejected";
}
}
(2) 定義一個對話框,框内有兩個按鈕
//Dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QWidget>
#include <QDebug>
#include <QPushButton>
#include <QtGui/QDialog>
class Dialog : public QDialog
{
Q_OBJECT
protected:
QPushButton Btn1; //對話框内按鈕1
QPushButton Btn2; //對話框内按鈕2
protected slots:
void Btn1_Clicked(); //按鈕1的槽
void Btn2_Clicked(); //按鈕2的槽
public:
Dialog(QWidget *parent = );
~Dialog();
};
#endif // DIALOG_H
#include "Dialog.h"
//Dialog類的構造函數,初始化清單指定兩個按鈕的父視窗都為Dialog
Dialog::Dialog(QWidget *parent) : QDialog(parent), Btn1(this), Btn2(this)
{
//初始化按鈕1
Btn1.setText("Btn1");
Btn1.move(, );
Btn1.resize(, );
//初始化按鈕2
Btn2.setText("Btn2");
Btn2.move(, );
Btn2.resize(, );
//初始化對話框的大小以及設定其名字
this->resize(, );
this->setWindowTitle("Dialog");
//信号與槽的映射
connect(&Btn1, SIGNAL(clicked()), this, SLOT(Btn1_Clicked()));
connect(&Btn2, SIGNAL(clicked()), this, SLOT(Btn2_Clicked()));
}
Dialog::~Dialog()
{
}
//按鈕1的槽
void Dialog::Btn1_Clicked()
{
qDebug() << "Btn1_Clicked()";
done(Accepted);
}
//按鈕2的槽
void Dialog::Btn2_Clicked()
{
qDebug() << "Btn2_Clicked()";
done(Rejected);
}
(3) main函數
//main.cpp
#include "Dialog.h"
#include "Widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
隻有模态對話框才有傳回值的概念,傳回值用于表示對話框和使用者的互動結果。函數:
void QDialog::done(int);
用于關閉對話框并将參數i作為與使用者的互動結果,發回給exec()的調用處。i的取值可為Accepted、Rejected或其其他int型資料,Accepted、Rejected是在QDialog類中定義的枚舉類型,前者表示使用者操作成功,後者表示操作失敗。
非模态對話框:
在棧中建立模态對話框是常用的方式,而非模态對話框由于其顯示函數是非阻塞的,是以需要在堆中建立。Widget::Btn_Clicked()函數改寫為:
void Widget::Btn_Clicked()
{
qDebug() << "Btn_Clicked()";
Dialog* d = new Dialog();
d->setAttribute(Qt::WA_DeleteOnClose);
d->show();
qDebug() << "Btn_Clicked() exit!";
}
show()函數是非阻塞的,對話框Dialog對象d若是在棧中生成那函數退出後對話框也随之消失,是以非模态對話框需在堆中動态生成,這樣該函數退出後對話框仍能顯示,但是卻也出現了新的問題:指針d執行動态生成的空間,一旦該函數退出後,d指針将失效,這也就意味着其他函數無法釋放該堆空間,造成記憶體洩漏。是以Qt提供了“對話框被使用者關閉後就釋放給對話框占據的堆空間”的操作:
Qt對話框的模态/非模态是通過對話框的屬性變量modal确定的,modal是個bool類型的變量,預設情況下是false,即非模态,是以調用show()函數顯示對話框時是非模态的;調用exec()函數顯示時,它将忽略modal的屬性值的設定并将對話框設定為模态對話框。
除了模态、非模态,還有一種混合特性的對話框,即通過QDialog::setModal()函數設定modal變量為true,那麼該對話框将變成:對話框在堆中配置設定,同時用show()顯示的前提下,同時又是模态對話框。
QDialog* dialog = new QDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setModal(true);
dialog->show();
2. Qt中定義的常用對話框
Qt提供了一些可複用的常用對話框類,這些類都繼承自QDialog類,有描述提示型消息的QMessageBox、描述檔案相關的QFileDialog、描述列印機選擇的QPrintDialog,描述顔色選擇的QColorDialog等等。
對于這些對話框類的使用,都遵循如下規則:
//1. 定義對話框
Dialogxxx d(this);
//2. 設定對話框屬性,如對話框标題、文字顯示
d.setxxx(xxx);
//3. 判斷對話框被使用者操作後的傳回值,
if (d.exec() == Dialogxxx::xxx)
{
//執行相關操作
}
下面是上述Qt實作好的對話框類的使用,它們定義在Widget類型的父類視窗類中的按鈕槽函數中。
2.1 消息對話框
消息對話框主要用于為使用者提示消息,強制使用者進行選擇:
//提示使用者消息
#include <QMessageBox>
//強制使用者選擇
QMessageBox msg(this); //建立對話框
msg.setWindowTitle("xxxx"); //設定對話框标題
msg.setText("customMsgBtnClicked"); //設定對話框的提示資訊
msg.setIcon(QMessageBox::Warning); //設定對話框的圖示
//設定對話框的按鈕
msg.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel | QMessageBox::YesToAll);
QMessageBox msg(this);
msg.setText("this is a message dialog!");
msg.exec();
運作結果:
2.2 檔案對話框
在GUI程式中,打開檔案和儲存檔案的時候都會彈出對話框,
//GUI程式要打開系統上的檔案
#include <QFileDialog>
QFileDialog d(this); //建立對話框
d.setAcceptMode(QFileDialog::AcceptOpen); //設定該對話框的模式為打開
d.setFileMode(QFileDialog::ExistingFiles); //選擇打開的是檔案,ExistingFiles表可選擇多檔案,
//ExistingFile則表示隻能選擇一個檔案,目錄則是QFileDialog::Directory
d.setFilter("TEXT(*.txt)"); //以檔案格式過濾掉檔案
if (d.exec() == QFileDialog::Accepted) //執行成功
{
QStringList fs = d.selectedFiles(); //列印使用者選擇的結果
for (int i = ; i < fs.count(); i++)
{
qDebug() << fs[i];
}
}
運作結果:
//GUI程式要儲存檔案
QFileDialog d(this);
d.setAcceptMode(QFileDialog::AcceptSave);
//d.setFilter("c(*.c)");
if (d.exec() == QFileDialog::Accepted)
{
QStringList fs = d.selectedFiles();
for (int i = ; i < fs.count(); i++)
{
qDebug() << fs[i];
}
}
運作:
2.3 顔色對話框
#include <QColorDialog>
QColorDialog d(this);
d.setWindowTitle("color editor");
if (d.exec() == QColorDialog::Accepted)
{
QColor color = d.selectedColor();
qDebug() << color;
qDebug() << color.red();
qDebug() << color.green();
qDebug() << color.blue();
}
運作:
setCurrentColor()函數用于設定目前的顔色值:
QColor類用于表現顔色值,該類有一個構造函數:
QColor ( int r, int g, int b, int a = )
2.4 輸入對話框
輸入對話框QInputDialog類,用于需要臨時進行資料輸入的場合:
QInputDialog d(this);
d.setWindowTitle("input dat");
d.setLabelText("ple input dat");
d.setInputMode(QInputDialog::IntInput); //TextInput輸入文本,DoubleInput輸入double類型
if (d.exec() == QInputDialog::Accepted)
qDebug() << d.intValue(); //TextValue、doubleValue
運作:
2.5 字型對話框
QFontDialog類用于選擇字型的對話框:
#include <QFontDialog>
QFontDialog f(this);
f.setWindowTitle("font select");
f.setCurrentFont(QFont(QFont("gargi", , QFont::Bold))); //設定彈出的對話框的選擇的字型
if (f.exec() == QFontDialog::Accepted)
{
qDebug() << f.selectedFont();
}
運作:
2.6 進度對話框
QProgressDialog類用于顯示進度資訊,不需要判斷exec()函數的傳回值:
#include <QProgressDialog>
QProgressDialog d(this);
d.setWindowTitle("load");
//設定範圍值
d.setMinimum();
d.setMaximum();
//設定進度數值
d.setValue();
//設定提示資訊
d.setLabelText("xxxxxxxx");
d.exec();
運作:
2.7 列印對話框
QPrinter類封裝了列印裝置驅動及其參數,利用該類尅以相同的方式使用系統的不同的列印裝置列印。
#include <QPrintDialog>
#include <QTextDocument>
#include <QPrinter>
QPrintDialog d(this);
d.setWindowTitle("print test");
if (d.exec() == QPrintDialog::Accepted)
{
QPrinter *p = d.printer();
QTextDocument td;
//可以通過列印機列印,這裡是列印到文本檔案
td.setPlainText("print test!!"); //待列印的文本
p->setOutputFileName("./tt.txt"); //列印到此檔案
td.print(p);
}
運作: