对话框是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 = 0); //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(80, 30);
Btn.move(40, 40);
Btn.setText("btn");
resize(240, 100);
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 = 0);
~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(20, 20);
Btn1.resize(100, 30);
//初始化按钮2
Btn2.setText("Btn2");
Btn2.move(140, 20);
Btn2.resize(100, 30);
//初始化对话框的大小以及设置其名字
this->resize(260, 70);
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提供了“对话框被用户关闭后就释放给对话框占据的堆空间”的操作:
d->setAttribute(Qt::WA_DeleteOnClose);
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 = 0; 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 = 0; 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()函数用于设置当前的颜色值:
d.setCurrentColor(QColor(100, 100, 100));
QColor类用于表现颜色值,该类有一个构造函数:
QColor ( int r, int g, int b, int a = 255 )
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", 10, QFont::Bold))); //设置弹出的对话框的选择的字体
if (f.exec() == QFontDialog::Accepted)
{
qDebug() << f.selectedFont();
}
运行:
2.6 进度对话框
QProgressDialog类用于显示进度信息,不需要判断exec()函数的返回值:
#include <QProgressDialog>
QProgressDialog d(this);
d.setWindowTitle("load");
//设置范围值
d.setMinimum(0);
d.setMaximum(100);
//设置进度数值
d.setValue(96);
//设置提示信息
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);
}
运行: