Qt 窗口 - 3
5. 对话框
5.1 对话框介绍
对话框是 GUI 程序中不可或缺的组成部分。一些不适合在主窗口实现的功能组件可以设置在对话框中。对话框通常是一个顶层窗口,出现在程序最上层,用于实现短期任务或者简洁的用户交互。Qt 中使用 QDialog 类表示对话框,Qt 常用的内置对话框有:QFileDialog
(文件对话框)、QColorDialog
(颜色对话框)、QFontDialog
(字体对话框)、QInputDialog
(输入对话框)和 QMessageBox
(消息框)。
针对一个已有的项目,也可以创建一些类,继承自 QDialog 实现咱们自定义的对话框!
我们打开某些网站,不经意间就会弹出各种奇奇怪怪的窗口,这就是对话框。
存在的意义就是和用户之间进行“短平快”的操作,比如:
我们可以写一个简单的示例来看看对话框:点击按钮,出现一个对话框:
void MainWindow::on_pushButton_clicked()
{QDialog* dialog = new QDialog(this);// 设置对话框的尺寸dialog->resize(200, 100);// 通过 show 方法就可以显示出对话框dialog->show();
}
注意:不同于界面上的其他控件,此处的 QDialog 每次按下按钮,都会创建一个新的 QDialog 对象,并进行显示。
这就会导致一个程序运行过程中,可以无数次点击这个按钮,进一步就会产生出无数个这样的对象,也就导致了内存泄漏了!
我们的解决办法就是当用户点击对话框的关闭按钮的时候,再来触发 delete 操作!
Qt 为了让咱们写的方便,直接给 QDialog 设置了一个属性,可以通过设置属性,完成了上述效果:
void MainWindow::on_pushButton_clicked()
{QDialog* dialog = new QDialog(this);// 设置对话框的尺寸dialog->resize(200, 100);// 通过 show 方法就可以显示出对话框dialog->show();dialog->setAttribute(Qt::WA_DeleteOnClose);
}
我们想要自定义对话框的话,就需要继承自 QDialog 创建类:
1.纯代码的方式来自定义 QDialog 界面
dialog.cpp:
Dialog::Dialog(QWidget *parent):QDialog(parent)
{// 创建出一些控件,加入到 Dialog 中,(以 Dialog 作为父窗口)QVBoxLayout* layout = new QVBoxLayout();this->setLayout(layout);QLabel* label = new QLabel("这是一个对话框", this);QPushButton* button = new QPushButton("关闭", this);layout->addWidget(label);layout->addWidget(button);connect(button, &QPushButton::clicked, this, &Dialog::handle);
}void Dialog::handle()
{this->close();
}
mainWindow.cpp:
void MainWindow::on_pushButton_clicked()
{Dialog* dialog = new Dialog(this);//由于这个窗口后续我们手动进行释放的,不必加到对象树上,想加也可以,就是需要修改其构造函数// ============================// // Dialog();// Dialog(QWidget* parent);// .cpp 也要改// ============================dialog->resize(400, 300);dialog->setAttribute(Qt::WA_DeleteOnClose);dialog->show();
}
2.通过图形化的方式
关键操作:创建出一个新的 ui 文件出来:
这个操作就是创建出一个 ui 文件,以及对应的类!
后续的操作就是在创建的 ui 文件中进行编辑了,然后:
void MainWindow::on_pushButton_clicked()
{// 弹出自定义的对话框Dialog* dialog = new Dialog(this);dialog->setAttribute(Qt::WA_DeleteOnClose);dialog->show();
}
void Dialog::on_pushButton_clicked()
{this->close();
}
5.2 对话框的分类
对话框分为 模态(model)对话框 和 非模态对话框。
model 其实就是一个 bool 值
5.2.1 模态对话框
模态对话框指的是:显示后无法与父窗口进行交互,是一种阻塞式的对话框。使用 QDialog::exec()
函数调用。
也就是模态对话框就是对于弹出对话框的时候,此时用户无法操作父窗口,必须得完成对话框内部的操作,关闭对话框之后,才可以继续操作父窗口!
模态对话框适用于必须依赖用户选择的场合,比如消息显示,文件选择,打印设置等。
示例:
新建 Qt 项目,在
ui
文件中的菜单栏中设置两个菜单:“文件”和“编辑”,在菜单“文件”下新建菜单项“新建”并将菜单项“新建”置于工具栏中;如下图所示:在
mainwindow.cpp
文件中实现:当点击“新建”时,弹出一个模态对话框; 说明:在菜单项中,点击菜单项就会触发triggered()
信号。#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDialog>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);connect(ui->actionnew, &QAction::triggered, this, [&]() {QDialog dlg(this);dlg.resize(200, 100);dlg.exec();}); }
5.2.2 非模态对话框
非模态对话框显示后独立存在,可以同时与父窗口进行交互,是一种非阻塞式对话框,使用 QDialog::show()
函数调用。
非模态对话框一般在堆上创建,这是因为如果创建在栈上时,弹出的非模态对话框就会一闪而过
同时还需要设置 Qt::WA_DeleteOnClose
属性,目的是:当创建多个非模态对话框时(打开了多个非模态窗口),为了避免内存泄漏需要设置此属性。
非模态对话框适用于特殊功能设置的场合,比如查找操作,属性设置等。
示例:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDialog>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);connect(ui->actionnew, &QAction::triggered, this, [&]() {QDialog *dlg = new QDialog(this);dlg->setAttribute(Qt::WA_DeleteOnClose);// 设置对话框的尺寸dlg->resize(200, 100);// 通过 show 方法就可以显示出对话框dlg->show();});
}
5.2.3 混合属性对话框
混合属性对话框同时具有模态对话框和非模态对话框的属性,对话框的生成和销毁具有非模态对话框属性,功能上具有模态对话框的属性。
使用 QDialog::setModal(true)
函数可以创建混合特性的对话框。通常,创建对话框时需要指定对话框的父组件。
示例:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDialog>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);connect(ui->actionnew, &QAction::triggered, this, [&]() {QDialog* dialog = new QDialog(this);dialog->setAttribute(Qt::WA_DeleteOnClose);dialog->setModal(true);dialog->resize(200, 100);dialog->show();});
}
5.3 Qt 内置对话框
Qt 提供了多种可复用的对话框类型,即 Qt 标准对话框。Qt 标准对话框全部继承于 QDialog
类。常用标准对话框如下:
QMessageBox
QFileDialog
QInputDialog
QFontDialog
QPrintDialog
QProgressDialog
5.3.1 消息对话框 QMessageBox
消息对话框是应用程序中最常用的界面元素。消息对话框主要用于为用户提供重要信息,强制用户进行选择操作。(常用于模态)
QMessageBox
类中定义了静态成员函数,可以直接调用创建不同风格的消息对话框,其中包括:
Question
:用于正常操作过程中的提问Information
:用于报告正常运行信息Warning
:用于报告非关键错误Critical
:用于报告严重错误
其对应的函数原型如下:
// 问题提示消息对话框
QMessageBox::question(QWidget *parent = nullptr, const QString &title = QString(), const QString &text = QString(), QMessageBox::StandardButton buttons = QMessageBox::StandardButton(QMessageBox::NoButton), QMessageBox::StandardButton *clickedButton = nullptr);// 信息提示消息对话框
QMessageBox::information(QWidget *parent = nullptr, const QString &title = QString(), const QString &text = QString(), QMessageBox::StandardButton buttons = QMessageBox::StandardButton(QMessageBox::NoButton), QMessageBox::StandardButton *clickedButton = nullptr);// 警告提示消息对话框
QMessageBox::warning(QWidget *parent = nullptr, const QString &title = QString(), const QString &text = QString(), QMessageBox::StandardButton buttons = QMessageBox::StandardButton(QMessageBox::NoButton), QMessageBox::StandardButton *clickedButton = nullptr);// 错误提示消息对话框
QMessageBox::critical(QWidget *parent = nullptr, const QString &title = QString(), const QString &text = QString(), QMessageBox::StandardButton buttons = QMessageBox::StandardButton(QMessageBox::NoButton), QMessageBox::StandardButton *clickedButton = nullptr);
示例1:错误消息对话框
void MainWindow::on_pushButton_clicked()
{// 创建 QMessageBoxQMessageBox* messageBox = new QMessageBox(this);messageBox->setWindowTitle("对话框窗口标题");messageBox->setText("这是对话框的文本");messageBox->setIcon(QMessageBox::Warning);// 标准按钮中,根本就没法进行信号槽的连接。(按钮是 QMessageBox 自己生成的)messageBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Save | QMessageBox::Cancel);// QPushButton* button = new QPushButton("按钮", messageBox);// messageBox->.addButton(button, QMessageBox::AcceptRole);// connect 连接信号槽,来针对当前点击的按钮进行一些相关操作。// 非模态的弹框。QMessageBox 使用场景更多的是模态的。// messageBox->show();// 弹出模态对话框,当对话框处于弹出状态的时候,代码就会在 exec 这里阻塞,一直到对话框被关闭。// 用户点击按钮,使对话框关闭之后,此时就能通过 exec 的返回值,来知道用户点击的是哪个按钮,从而执行一些对应的逻辑了。int result = messageBox->exec();// 其返回值就是对应的设置的按钮的枚举值!if (result == QMessageBox::Ok) {qDebug() << "OK";} else if (result == QMessageBox::Save) {qDebug() << "Save";}else if (result == QMessageBox::Cancel){qDebug() << "Cancel";}// delete messageBox;messageBox->setAttribute(Qt::WA_DeleteOnClose);
}
实现效果如下:
其中可以设置的按钮的类型如下:
Constant | Value | Description |
---|---|---|
QMessageBox::Ok | 0x00000000 | An "OK" button defined with the AcceptRole. |
QMessageBox::Open | 0x00000002 | An "Open" button defined with the AcceptRole. |
QMessageBox::Save | 0x00000008 | A "Save" button defined with the AcceptRole. |
QMessageBox::Cancel | 0x00000040 | A "Cancel" button defined with the RejectRole. |
QMessageBox::Close | 0x00020000 | A "Close" button defined with the RejectRole. |
QMessageBox::Discard | 0x00080000 | A "Discard" or "Don't Save" button, depending on the platform. |
QMessageBox::Apply | 0x02000000 | An "Apply" button defined with the ApplyRole. |
QMessageBox::Reset | 0x04000000 | A "Reset" button defined with the ResetRole. |
QMessageBox::RestoreDefaults | 0x80000000 | A "Restore Defaults" button defined with the ResetRole. |
QMessageBox::Help | 0x00100000 | A "Help" button defined with the HelpRole. |
QMessageBox::SaveAll | 0x00010000 | A "Save All" button defined with the AcceptRole. |
QMessageBox::Yes | 0x00000080 | A "Yes" button defined with the YesRole. |
QMessageBox::YesToAll | 0x00000040 | A "Yes to All" button defined with the YesRole. |
QMessageBox::No | 0x00000020 | A "No" button defined with the NoRole. |
QMessageBox::NoToAll | 0x00020000 | A "No to All" button defined with the NoRole. |
QMessageBox::Abort | 0x00040000 | An "Abort" button defined with the RejectRole. |
QMessageBox::Retry | 0x00080000 | An "Retry" button defined with the RejectRole. |
QMessageBox::Ignore | 0x00100000 | An "Ignore" button defined with the AcceptRole. |
QMessageBox::NoButton | 0x00000000 | An invalid button. |
示例2:信息提示消息对话框/问题提示消息对话框/错误提示消息对话框
我们如果是只需要简单的弹出一个相应的对话框,就没有必要写得向上面那样,直接借助下面这样的静态函数,直接就可以构造出来!
如果需要往对话框中设置一些自定义的按钮,我们就需要老老实实创建出 QMessageBox 对象,往其一个一个属性的进行添加,然后完成添加自定义按钮的过程!
void MainWindow::on_pushButton_clicked()
{// int result = QMessageBox::warning(this, "对话框标题", "对话框问文本", QMessageBox::Ok | QMessageBox::Cancel);// int result = QMessageBox::critical(this, "对话框标题", "对话框问文本", QMessageBox::Ok | QMessageBox::Cancel);// int result = QMessageBox::information(this, "对话框标题", "对话框问文本", QMessageBox::Ok | QMessageBox::Cancel);int result = QMessageBox::question(this, "对话框标题", "对话框问文本", QMessageBox::Ok | QMessageBox::Cancel);if(result == QMessageBox::Ok){qDebug() << "Ok";}else if(result == QMessageBox::Cancel){qDebug() << "Cancel";}
}
5.3.2 颜色对话框 QColorDialog
颜色对话框的功能是允许用户选择颜色。继承自 QDialog
类。
Qt QColorDialog 的功能就是 Qt 内置的调色板!
常用方法介绍:
QColorDialog (QWidget *parent = nullptr);
// 创建对象的同时设置父对象
QColorDialog(const QColor &initial, QWidget *parent = nullptr);
// 创建对象的同时通过 QColor 对象设置默认颜色和父对象
void setCurrentColor(const QColor &color);
// 设置当前颜色对话框
QColor currentColor() const;
// 获取当前颜色对话框
QColor getColor(const QColor &initial = Qt::white, QWidget *parent = nullptr, const QString &title = QString(), QColorDialog::ColorDialogOptions options = ColorDialogOptions());(最常用)
// 打开颜色选择对话框,并返回一个 QColor 对象,也就是说:这个函数就能够弹出一个对话框,用户选择颜色之后,点击确认,对话框关闭,getColor 返回的值,就是用户选择的颜色值!
//是一个静态函数(static)和 QMessageBox::warning 一样,不需要创建对话框对象,就可以直接使用!
参数说明:
initial
:设置默认颜色parent
:设置父对象title
:设置对话框标题options
:设置选项
示例1:
void MainWindow::on_pushButton_clicked()
{// QColorDialog* dialog = new QColorDialog(this);// dialog->exec();// delete dialog;// 函数的返回值就是用户选择的颜色QColor color = QColorDialog::getColor(QColor(0, 255, 0), this, "选择颜色");qDebug()<<color;// 可以居于用户选择的颜色,修改窗口的背景色// 可以通过 QSS 的方式设置背景色// QString style = "background-color: rgb(" + QString::number(color.red()) + ", " +// QString::number(color.green()) + ", " +// QString::number(color.blue()) + ");";// 也可以这么写char style[1024] = {0};sprintf(style, "background-color: rgb(%d, %d, %d);", color.red(), color.green(), color.blue());this->setStyleSheet(style);
}
效果如下:
5.3.3 文件对话框 QFileDialog
文件对话框用于应用程序中需要打开一个外部文件或需要将当前内容存储到指定的外部文件。
常用方法介绍:
1.打开文件(一次只能打开一个文件)
QString getOpenFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = QFileDialog::Options());
2.打开多个文件(一次可以打开多个文件)
QStringList getOpenFileNames(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = QFileDialog::Options());
3.保存文件
QString getSaveFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = QFileDialog::Options());
参数说明:
参数1:
parent
父对象参数2:
caption
对话框标题参数3:
dir
默认打开的路径参数4:
filter
文件过滤器
示例1:打开文件
void MainWindow::on_pushButton_clicked()
{QString filepath = QFileDialog::getOpenFileName(this);qDebug() << filepath;
}
运行效果:
示例2:保存文件
void MainWindow::on_pushButton_2_clicked()
{QString filepath = QFileDialog::getSaveFileName(this);qDebug() << filepath;
}
运行效果:
5.3.4 字体对话框 QFontDialog
Qt 中提供了预定义的字体对话框类 QFontDialog
,用于提供选择字体的对话框部件。
示例:
void MainWindow::on_pushButton_clicked()
{bool ok = false;QFont font = QFontDialog::getFont(&ok);qDebug() << "ok: " << ok;// qDebug() << "font: " << font;qDebug() << font.family();qDebug() << font.pointSize();qDebug() << font.bold();qDebug() << font.italic();ui->pushButton->setFont(font);
}
运行效果如下:
5.3.5 输入对话框 QInputDialog
Qt 中提供了预定义的输入对话框类:QInputDialog
,用于进行临时数据输入的场合。
常用方法介绍:
1.双精度浮点型输入数据对话框
double getDouble(QWidget *parent, const QString &title, const QString &label, double value = 0, double min = -2147483647, double max = 2147483647, int decimals = 1, bool *ok = nullptr, Qt::WindowFlags flags = {});
2.整型输入数据对话框
int getInt(QWidget *parent, const QString &title, const QString &label, int value = 0, int min = -2147483647, int max = 2147483647, int step = 1, bool *ok = nullptr, Qt::WindowFlags flags = {});
3.选择条目型输入数据对话框
QString getItem(QWidget *parent, const QString &title, const QString &label, const QStringList &items, int current = 0, bool editable = true, bool *ok = nullptr, Qt::WindowFlags flags = {});
参数说明:
parent
:父对象title
:对话框标题label
:可供选择的条目
示例1:浮点型数据输入对话框
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include <QInputDialog>
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QPushButton *btn = new QPushButton("输入框", this);connect(btn, &QPushButton::clicked, [=]() {double d = QInputDialog::getDouble(this, "输入框", "浮点型");qDebug() << "d = " << d;});
}
示例2:整型数据输入对话框
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include <QInputDialog>
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QPushButton *btn = new QPushButton("输入框", this);connect(btn, &QPushButton::clicked, [=]() {int i = QInputDialog::getInt(this, "输入框", "Int");qDebug() << "i = " << i;});
}
示例3:打开选择条目对话框
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include <QInputDialog>
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QPushButton *btn = new QPushButton("输入框", this);connect(btn, &QPushButton::clicked, [=]() {QStringList items;items << tr("Spring") << tr("Summer") << tr("Fall") << tr("Winter");QString item = QInputDialog::getItem(this, "输入框", "Item", items);qDebug() << "item." << item.toUtf8().data(); }); }
}
窗口总结
菜单栏(QMenuBar)--- 菜单(QMenu)--- 菜单项(QAction)
工具栏(QToolBar)(具有多个)--- 菜单项(QAction)
子窗口(QDockWidget)--- QWidget --- 放置其他的控件
状态栏(QStatusBar)--- QWidget
对话框(QDialog)--- 自己手动继承的方式,针对 QDialog 进行扩展
这样我们就可以得到更完整的应用程序!