个人博客地址
|----------------------------------------|
| 个人博客: 花开富贵 |
文章目录
- 个人博客地址
-
- [1 对话框基本概念](#1 对话框基本概念)
- [2 创建简单的对话框](#2 创建简单的对话框)
- [3 对话框的内存管理问题](#3 对话框的内存管理问题)
- [4 自定义对话框](#4 自定义对话框)
-
- [4.1 纯代码自定义对话框](#4.1 纯代码自定义对话框)
- [4.2 UI与代码结合自定义对话框](#4.2 UI与代码结合自定义对话框)
- [5 对话框的模态与非模态](#5 对话框的模态与非模态)
- [6 内置对话框](#6 内置对话框)
-
- [6.1 QMessageBox 消息对话框](#6.1 QMessageBox 消息对话框)
-
- [6.1.1 通过按钮判断执行逻辑](#6.1.1 通过按钮判断执行逻辑)
- [6.2 QColorDialog 颜色对话框](#6.2 QColorDialog 颜色对话框)
-
- [6.2.1 QColorDialog 返回值](#6.2.1 QColorDialog 返回值)
- [6.3 QFileDialog 文件对话框](#6.3 QFileDialog 文件对话框)
- [6.5 QFontDialog 字体对话框](#6.5 QFontDialog 字体对话框)
- [6.6 QInputDialog 输入对话框](#6.6 QInputDialog 输入对话框)
1 对话框基本概念
对话框是一个弹窗, 通常用于进行一些与与用户间的=="短平快"==操作;
典型的为是当对一个已编辑文件进行退出操作时, 将会弹出弹窗询问是否进行保存;

在Qt中, 通常表示QDialog来表示一个对话框;
针对已有的项目, 也可以创建一些类, 继承自对应的QDialog以完成自定义的对话框, 同时QT也提供了一些内置的对话框, 以静态函数的形式, 方便快速使用对话框以避免自定义对话框;
常见的内置对话框有:
QFiledialog(文件对话框)QColorDialog(颜色对话框)QFontDialog(字体对话框)QInputDialog(输入对话框)QMessageBox(消息框)
2 创建简单的对话框
可以在QtCreator中创建一个简单的对话框;

从运行结果来看, 实际上对话框与QWidget类似;
本质上是因为, QDialog对象继承自QWidget类;

在QWidget的基础上添加了两个属性, 分别为sizeGripEnable与modal;
其中sizeGripEnable表示右下角的可拖动放大缩小, modal属性则是为是否为非模态(模态/非模态将在下文进行介绍)对话框;
3 对话框的内存管理问题
该话题开始之前, 我们需要设计一个小程序, 即在QMainWindow中存在一个PushButton, 当按下Button后, 将会弹出一个弹窗;
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
void MainWindow::on_pushButton_clicked()
{
QDialog* dialog = new QDialog(this);
dialog->setWindowTitle("弹窗标题");
dialog->resize(200, 100);
dialog->show();
}
运行结果为:

那么这里将存在一个问题, 在上面的代码中, 我们把这个Dialog的父对象设置为QMainWindow, 但是在关闭过程中, 内存是否会进行释放? 即真正意义上的关闭;
我们需要了解一下, 当一个窗口的内存被释放(析构)后, 称这个窗口被关闭;
而实际在Qt中, 若是这个窗口是一个子窗口而不是主窗口, 当按下关闭键后并不会释放内存, 这意味着并不会真正的释放它的内存, 而是对其进行隐藏;
为了验证这一点, 我们构建一个新的Dialog, 继承自QDialog类, 来实现一个自己的Dialog, 判断其是否会调用析构函数, 完成内存释放;
通过新建class继承QDialog类设计一个myDialog;
cpp
/*mydialog.h*/
class myDialog : public QDialog
{
Q_OBJECT
public:
myDialog(QWidget *parent = nullptr);
~myDialog();
};
/*mydialog.cpp*/
myDialog::myDialog(QWidget *parent)
: QDialog(parent)
{
}
myDialog::~myDialog()
{
qDebug()<<"~myDialog()";
}
/*mainwindow.cpp*/
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
void MainWindow::on_pushButton_clicked()
{
myDialog* dialog = new myDialog(this);
dialog->setWindowTitle("弹窗标题");
dialog->resize(200, 100);
dialog->show();
}

从结果看到, 当点击右上角关闭按钮时, 析构函数并没有被调用, 因为其实际上是被隐藏而不是被真正意义上的关闭, 因此最后将QMainWindow关闭后, 由于所创建的myDialog对象在其对象树上, QMainWindow被关闭时将会逐个释放对象树中子树的内存, 导致所创建的三个myDialog在同一时间被释放;
因此需要控制其内存释放( 在拥有对象树属性的Qt中通常不允许在析构中通过delete this来释放内存以避免对象树在析构中产生差错);
通常可以通过设置 setAttribute()并传入 Qt::WA_DeleteOnClose作为参数, 表示设置当关闭右上角关闭按键时, 彻底关闭这个窗口并释放内存;
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
void MainWindow::on_pushButton_clicked()
{
myDialog* dialog = new myDialog(this);
dialog->setWindowTitle("弹窗标题");
dialog->resize(200, 100);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
}

从结果来看, 析构函数被调用, 说明当窗口被关闭时, 将释放内存;
除此之外, 也可以通过在Dialog中设置一个按钮, 通过信号槽的形式来关闭/释放对应的Dialog(这里同样要设置setAttribute来设置WA_DeleteOnClose);
cpp
myDialog::myDialog(QWidget *parent)
: QDialog(parent)
{
QPushButton* button = new QPushButton("Close Dialog");
QVBoxLayout* layout = new QVBoxLayout(this);
this->setLayout(layout);
layout->addWidget(button);
connect(button, &QPushButton::clicked, this, &myDialog::closeDialog);
}
myDialog::~myDialog()
{
qDebug()<<"~myDialog()";
}
void myDialog::closeDialog()
{
// delete this; // 不推荐(可能破坏对象树)
this->close(); // 推荐(但需要设置 setAttribute(WA_DeleteOnClose))
}
运行结果为:

4 自定义对话框
自定义对话框有两种方式, 一种为UI配合代码的方式, 另一种为纯代码的方式;
4.1 纯代码自定义对话框
通过纯代码的自定义对话框的方式在QtCreator中的步骤为如下:
-
文件->新建文件

-
选择
C++ Class
-
命名新类名/继承自哪个类以及勾选所需选项

完成后将会自动生成对应的头文件以及源文件;

当文件创建完毕后, 则可以对对应的对话框内设计内容, 类似的设计方式已在 "3 对话框的内存管理问题" 中有示例, 在此不进行赘述;
4.2 UI与代码结合自定义对话框
相同的步骤, 但所选项不同, 以下图为例:
-
选择
Qt -> QtWidget Designer Form Class
-
选择所需界面(此处为
QDialog的派生类, 因此此处选择Dialog Without Buttons)
-
设置类名

-
最终结果

最终可以看到, 选择结束后自动生成了
.ui,.h,.cpp文件;
具体的使用与正常的Widget无异, 此处不赘述;
同时所有需要自定义的控件都可以使用这种方式设置;
5 对话框的模态与非模态
对话框也分为模态与非模态;
-
模态
弹出对话框时, 父窗口无法操作, 必须等待对话框结束;
-
非模态
弹出对话框时, 不影响父窗口操作;
通常情况下, 模态对话框通常需要用户作出重大决策, 如当某个文件编辑后未保存, 在关闭时或许会弹出模块对话框提示"是否保存所编辑内容";
在Qt中, 我们可以通过QDialog::setModal(bool)来设置对应的模态状态, 当以show进行窗口显示时, 默认为非模态;
创建一个QMainWindow, 该QMainWindow中包含一个按钮, 通过点击按钮来弹出一个对话框;
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
void MainWindow::on_pushButton_clicked()
{
myDialog* dialog = new myDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
}
运行结果为:

可以看到, 在非模态的状态下, 当出现弹窗时, 父窗口仍进行点击;
此处调用setModal(true)再次运行程序;
cpp
void MainWindow::on_pushButton_clicked()
{
myDialog* dialog = new myDialog(this);
dialog->setModal(true);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
}
运行结果为:

当setModal设置为true时, 为模态弹窗, 此时用户必须使弹窗结束, 否则父窗口将阻塞;
在此前, 我们提到, 当使用show()展示窗口时将会出现这样的情况, 是因为本质上使用show()展示窗口时, 默认采用非模态的形式来展示, 若是需要模态窗口展示, 可以将show()替换为exec();
cpp
void MainWindow::on_pushButton_clicked()
{
myDialog* dialog = new myDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->exec();
}
运行结果与上图一致;
6 内置对话框
除了用户可以使用QDialog或者自定义对话框以外, Qt也提供了一系列的内置对话框以提供更便捷的开发;
常用的内置对话框有如下:
QMessageBox- 消息对话框QFileDialog- 文件对话框QInputDialog- 输入对话框QFontDialog- 字体对话框QPrintDialog- 打印对话框QProgressDialog- 进度条对话框
6.1 QMessageBox 消息对话框
QMessageBox消息对话框是Qt所提供的用于展示不同级别的消息内容的对话框;
通常情况下, 消息对话框是模态对话框, 当对话框弹出时, 用户必须在对话框内进行决策, 否则无法进行下一步操作;
cpp
void MainWindow::on_pushButton_clicked()
{
QMessageBox* msgbox = new QMessageBox(this);
msgbox->setWindowTitle("Title for QMessageBox"); // 设置标题
msgbox->setText("Text for QMessageBox"); // 设置文本
msgbox->setIcon(QMessageBox::Information); // 设置图标
msgbox->setStandardButtons(QMessageBox::Ok|QMessageBox::Save); // 设置按钮
msgbox->exec(); // 模态窗口展示
}
-
设置标题
调用
setWindowTitle(QString)来设置对应的弹窗标题; -
设置文本内容
调用
setText(QString)来设置文本内容; -
设置
Icon图标QMessageBox支持设置图标, 可以设置自定义的图标;除此之外,
QMessageBox内置了一些图标以供用户快速使用;cppenum Icon { // keep this in sync with QMessageDialogOptions::StandardIcon NoIcon = 0, // 没有图标 Information = 1, // 常规 Warning = 2, // 警告 Critical = 3, // 严重 Question = 4 // 问题 }; Q_ENUM(Icon)内置的图标通常来为消息进行级别划分, 可以直接传入枚举值来设置对应的图标;
-
设置按钮
在
QMessageBox中, 可通过setStandardButtons()来添加按钮;cppenum StandardButton { // keep this in sync with QDialogButtonBox::StandardButton and QPlatformDialogHelper::StandardButton NoButton = 0x00000000, Ok = 0x00000400, Save = 0x00000800, SaveAll = 0x00001000, Open = 0x00002000, Yes = 0x00004000, YesToAll = 0x00008000, No = 0x00010000, NoToAll = 0x00020000, Abort = 0x00040000, Retry = 0x00080000, Ignore = 0x00100000, Close = 0x00200000, Cancel = 0x00400000, Discard = 0x00800000, Help = 0x01000000, Apply = 0x02000000, Reset = 0x04000000, RestoreDefaults = 0x08000000, FirstButton = Ok, // internal LastButton = RestoreDefaults, // internal YesAll = YesToAll, // obsolete NoAll = NoToAll, // obsolete Default = 0x00000100, // obsolete Escape = 0x00000200, // obsolete FlagMask = 0x00000300, // obsolete ButtonMask = ~FlagMask // obsolete }; Q_ENUM(StandardButton)该函数的参数只有一个, 但是可以传入多个按钮, 本质是通过位运算的方式进行添加;
-
上述代码的运行结果为

除此之外, QMessageBox还派生了一系列的子类, 并设计了对应的静态成员函数, 可直接通过静态成员函数来设置需要的QMessageBox, 常见的有:
-
QMessageBox::Information用于报告正常运行信息;
-
QMessageBox::Question用于正常操作过程中的提问;
-
QMessageBox::Warning用于报告非关键错误;
-
QMessageBox::Critical用于报告严重错误;
示例:
cpp
void MainWindow::on_pushButton_clicked()
{
QMessageBox::critical(this, "CriticalTitle", "Critical", QMessageBox::Ok|QMessageBox::Cancel);
}
运行结果为:

6.1.1 通过按钮判断执行逻辑
可见, 由于并不能制定槽函数, 因此无法以以往的方式对按钮进行区分操作, 即判断哪个按钮被按下;
而在exec()函数中, 将会返回一个返回值, 这个返回值通常为按钮按下的值;
可通过该值来判断所按下的按钮;
除此之外, 静态成员函数QMessageBox::xxx也将返回一个返回值, 同样可以用来判断所按下的值;
cpp
void MainWindow::on_pushButton_clicked()
{
int res = QMessageBox::critical(this, "CriticalTitle", "Critical", QMessageBox::Ok|QMessageBox::Cancel);
switch (res) {
case QMessageBox::Ok:
qDebug()<<"QMessageBox::Ok";
break;
case QMessageBox::Cancel:
qDebug()<<"QMessageBox::Cancel";
break;
default:
qDebug()<<"No Button Clicked!";
}
}
运行结果为:

6.2 QColorDialog 颜色对话框
颜色对话框允许用户选择颜色, 同样继承于QDialog;

同样的, QColorDialog为了方便使用, 生成了对应的静态函数, 可直接通过QColorDialog::getColor()来打开颜色对话框;
cpp
void MainWindow::on_pushButton_clicked()
{
QColorDialog::getColor();
}
运行结果为:

6.2.1 QColorDialog 返回值
同样的, 这个对话框能返回所选择的颜色属性;
通常返回的是一个QColor类型的对象;
cpp
void MainWindow::on_pushButton_clicked()
{
QColor res = QColorDialog::getColor();
qDebug()<<res;
}
忽略运行图例, 运行(运行并获取颜色)结果为:
bash
QColor(ARGB 1, 0.254902, 0.329412, 1)
可以看到, 这里的QColor所返回的并不是一个RGB格式的颜色, 而是ARGB格式, 其中A表示alpha不透明度, 1表示完全不透明, 0表示完全透明, 其他的内容即为默认的RGB;
可以通过拼接字符串的形式, 设置对应的StyleSheet:
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setObjectName("QMainWindow_Test"); // 设置对象名
}
void MainWindow::on_pushButton_clicked()
{
QColor res = QColorDialog::getColor();
/*对应的StyleSheet只作用于QMainWindow_Test中*/
QString style = QString("#QMainWindow_Test { background-color: rgb(%1, %2, %3); }")
.arg(res.red())
.arg(res.green())
.arg(res.blue());
this->setStyleSheet(style);
qDebug()<<res;
}
运行结果为:

6.3 QFileDialog 文件对话框
同样是QDialog的派生类, 其能够打开文件对话框, 并且支持打开文件与保存文件的对话框;
这里以打开文件, 打开多个文件, 保存文件为例;

代码为:
cpp
void MainWindow::on_pushButton_clicked()
{
QString fileName = QFileDialog::getOpenFileName();
qDebug()<<fileName;
}
void MainWindow::on_pushButton_2_clicked()
{
QStringList fileNames = QFileDialog::getOpenFileNames();
qDebug()<<fileNames;
}
void MainWindow::on_pushButton_3_clicked()
{
QString fileName = QFileDialog::getSaveFileName();
qDebug()<<fileName;
}
运行结果为:
(图片过大, CSDN无法显示, 建议移步[Here!!!])

这个对话框也是后期针对QT的文件操作的一部分;
6.5 QFontDialog 字体对话框
字体对话框能够打开对话框并选择对应的字体;
可直接调用静态成员函数来打开QFOntDialog::getFont(&ok);
cpp
static QFont getFont(bool *ok, QWidget *parent = nullptr);
可以看到, 该函数必须的参数有一个bool类型的指针;
该指针可以用于判断该字体对话框最终的按钮点击为OK还是Cancel;
同时该函数将会返回一个QFont类型对象, 而该类型通常用来描述一个具体的字体信息, 可以其进行打印;
cpp
void MainWindow::on_pushButton_clicked()
{
bool ok;
QFont font = QFontDialog::getFont(&ok, this);
if(ok) qDebug()<<font;
else qDebug()<<"Cancel";
}
运行结果为:

在有些控件中, 可以通过setFont来设置对应的字体, 可以配合该对话框使用:
cpp
void MainWindow::on_pushButton_clicked()
{
bool ok;
QFont font = QFontDialog::getFont(&ok, this);
if(ok) {
ui->pushButton->setFont(font);
qDebug()<<font;
}
else qDebug()<<"Cancel";
}
运行结果为:
(图片过大, CSDN无法显示, 建议移步[Here!!!])

6.6 QInputDialog 输入对话框
弹出一个对话框, 该对话框将会让用户输入对应的内容;
所输入的内容可以是整数, 浮点数, 或是字符串;
通常直接调用静态成员函数直接使用;

代码为:
cpp
void MainWindow::on_pushButton_int_clicked()
{
int res = QInputDialog::getInt(this, "Get INT", "INT");
qDebug()<<res;
}
void MainWindow::on_pushButton_float_clicked()
{
double res = QInputDialog::getDouble(this, "Get DOUBLE", "DOUBLE");
qDebug()<<res;
}
void MainWindow::on_pushButton_str_clicked()
{
QString res = QInputDialog::getText(this, "Get STRING", "STRING");
qDebug()<<res;
}
void MainWindow::on_pushButton_item_clicked()
{
QString res = QInputDialog::getItem(this, "Get ITEM", "ITEM",{"Hello", "World", "Qt", "C++"});
qDebug()<<res;
}
运行结果为:
(图片过大, CSDN无法显示, 建议移步[Here!!!])
