QT入门第五天:对话框QDialog详解 | 零基础学QT
前言
前四天我们学习了环境搭建、信号与槽、常用控件、布局管理器,今天我们来学习对话框(QDialog)。
做软件的时候,我们经常需要弹出一些小窗口和用户交互,比如:
- 弹出一个提示"操作成功"
- 删除文件前问一句"确定要删除吗?"
- 让用户输入一些文字
- 选择一个文件打开或保存
- 选择颜色、字体
这些小窗口就是对话框。QT已经帮我们做好了很多常用的对话框,直接调用就行,不用自己从零开始写。
今天我们学习:
- 模态对话框 vs 非模态对话框
- QMessageBox 消息框(最常用)
- QInputDialog 输入对话框
- QFileDialog 文件对话框
- QColorDialog 颜色对话框
- QFontDialog 字体对话框
- 自定义对话框
一、模态对话框 vs 非模态对话框
在学习具体的对话框之前,先搞清楚两个重要概念:
1.1 模态对话框(Modal)
模态对话框弹出来之后,你不能操作后面的主窗口,必须先把这个对话框关掉,才能继续操作主窗口。
生活类比:就像你去银行办业务,柜员叫你填单子,你必须填完单子交给他,才能继续办下一个业务。
常见场景:
- 删除确认框(必须选是或否)
- 登录对话框(必须登录才能用软件)
- 重要的提示信息
1.2 非模态对话框(Modeless)
非模态对话框弹出来之后,你还可以操作后面的主窗口,两者互不影响。
生活类比:就像你一边看电视一边吃零食,电视还在播,你也可以吃零食,互不干扰。
常见场景:
- 查找替换对话框
- 工具箱面板
- 帮助窗口
1.3 怎么用
cpp
// 模态对话框:用 exec()
QDialog dialog;
dialog.exec(); // 程序会停在这里,直到对话框关闭
// 非模态对话框:用 show()
QDialog *dialog = new QDialog(this);
dialog->show(); // 弹出来就完事,程序继续往下走
💡 记住:模态用
exec(),非模态用show()。大部分常用对话框都是模态的。
二、QMessageBox 消息框
QMessageBox是最常用的对话框,用来显示提示信息,或者问用户一些简单的问题。
2.1 信息提示框
cpp
#include <QMessageBox>
// 信息提示(蓝色i图标)
QMessageBox::information(this, "提示", "操作成功!");
运行效果:弹出一个对话框,标题是"提示",内容是"操作成功!",有一个"确定"按钮。
2.2 警告框
cpp
// 警告提示(黄色感叹号图标)
QMessageBox::warning(this, "警告", "您的磁盘空间不足!");
2.3 错误框
cpp
// 错误提示(红色叉号图标)
QMessageBox::critical(this, "错误", "文件打开失败!");
2.4 询问框
这个最实用,问用户"是"还是"否":
cpp
// 询问(问号图标,有是和否两个按钮)
int ret = QMessageBox::question(this, "确认", "确定要删除吗?");
if (ret == QMessageBox::Yes) {
qDebug() << "用户点了是,执行删除";
} else {
qDebug() << "用户点了否,取消删除";
}
2.5 关于框
cpp
// 关于对话框(显示软件信息)
QMessageBox::about(this, "关于", "我的软件 v1.0\n作者:小明");
2.6 自定义按钮
默认的按钮不够用?你还可以自定义按钮:
cpp
// 自定义按钮:保存、不保存、取消
int ret = QMessageBox::question(
this,
"提示",
"文件已修改,是否保存?",
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
QMessageBox::Save // 默认选中的按钮
);
if (ret == QMessageBox::Save) {
qDebug() << "保存";
} else if (ret == QMessageBox::Discard) {
qDebug() << "不保存";
} else {
qDebug() << "取消";
}
常用按钮常量:
QMessageBox::Ok- 确定QMessageBox::Cancel- 取消QMessageBox::Yes- 是QMessageBox::No- 否QMessageBox::Save- 保存QMessageBox::Discard- 不保存/丢弃QMessageBox::Abort- 中止QMessageBox::Retry- 重试QMessageBox::Ignore- 忽略
💡 小技巧:多个按钮用
|(按位或)连起来。
三、QInputDialog 输入对话框
QInputDialog用来让用户输入一些内容,比如输入文字、数字、从列表中选一项。
3.1 输入文字
cpp
#include <QInputDialog>
bool ok;
QString text = QInputDialog::getText(
this,
"输入",
"请输入你的名字:",
QLineEdit::Normal, // 输入模式(正常/密码等)
"默认文字", // 默认值
&ok // 用户是否点了确定
);
if (ok && !text.isEmpty()) {
qDebug() << "用户输入了:" << text;
}
3.2 输入数字
cpp
// 输入整数
int num = QInputDialog::getInt(
this,
"输入",
"请输入一个数字:",
10, // 默认值
0, // 最小值
100, // 最大值
1, // 步长(点一下加减多少)
&ok
);
// 输入小数(浮点数)
double value = QInputDialog::getDouble(
this,
"输入",
"请输入价格:",
99.99, // 默认值
0, // 最小值
9999, // 最大值
2, // 小数位数
&ok
);
3.3 下拉选择
让用户从一个列表中选一项:
cpp
QStringList items;
items << "苹果" << "香蕉" << "橙子" << "葡萄";
QString item = QInputDialog::getItem(
this,
"选择",
"请选择你喜欢的水果:",
items, // 选项列表
0, // 默认选中第几项
false, // 是否可编辑(false只能选,true还能自己输入)
&ok
);
if (ok) {
qDebug() << "用户选择了:" << item;
}
3.4 多行文本
cpp
QString text = QInputDialog::getMultiLineText(
this,
"输入",
"请输入备注:",
"默认内容",
&ok
);
四、QFileDialog 文件对话框
QFileDialog用来让用户选择文件或目录,比如打开文件、保存文件、选择文件夹。
4.1 打开单个文件
cpp
#include <QFileDialog>
QString fileName = QFileDialog::getOpenFileName(
this,
"打开文件", // 对话框标题
"", // 默认打开的目录(空表示当前目录)
"文本文件 (*.txt);;图片文件 (*.png *.jpg);;所有文件 (*.*)" // 文件过滤器
);
if (!fileName.isEmpty()) {
qDebug() << "选择的文件:" << fileName;
}
文件过滤器格式说明:
"文本文件 (*.txt)"- 显示txt文件- 多个类型用
;;分隔 - 同一类型多个后缀用空格分隔,如
"图片文件 (*.png *.jpg)"
4.2 打开多个文件
cpp
QStringList fileNames = QFileDialog::getOpenFileNames(
this,
"选择多个文件",
"",
"所有文件 (*.*)"
);
qDebug() << "选择了" << fileNames.size() << "个文件";
4.3 保存文件
cpp
QString fileName = QFileDialog::getSaveFileName(
this,
"保存文件",
"untitled.txt", // 默认文件名
"文本文件 (*.txt)"
);
if (!fileName.isEmpty()) {
qDebug() << "保存到:" << fileName;
}
4.4 选择目录
cpp
QString dirName = QFileDialog::getExistingDirectory(
this,
"选择文件夹",
""
);
if (!dirName.isEmpty()) {
qDebug() << "选择的文件夹:" << dirName;
}
五、QColorDialog 颜色对话框
QColorDialog用来让用户选择颜色,比如设置文字颜色、背景颜色。
cpp
#include <QColorDialog>
QColor color = QColorDialog::getColor(
Qt::red, // 默认颜色
this,
"选择颜色"
);
if (color.isValid()) {
qDebug() << "选择的颜色:" << color.name(); // 比如 #ff0000
}
选完颜色后,你可以用这个颜色来设置控件的样式:
cpp
// 比如设置按钮的背景色
QPushButton *btn = new QPushButton("按钮");
btn->setStyleSheet(QString("background-color: %1;").arg(color.name()));
六、QFontDialog 字体对话框
QFontDialog用来让用户选择字体,比如设置文字的字体、大小、加粗、斜体。
cpp
#include <QFontDialog>
bool ok;
QFont font = QFontDialog::getFont(
&ok,
QFont("微软雅黑", 12), // 默认字体
this,
"选择字体"
);
if (ok) {
qDebug() << "字体:" << font.family();
qDebug() << "大小:" << font.pointSize();
qDebug() << "加粗:" << font.bold();
qDebug() << "斜体:" << font.italic();
}
设置字体给控件:
cpp
QLabel *label = new QLabel("Hello");
label->setFont(font);
七、QProgressDialog 进度对话框
QProgressDialog用来显示操作进度,比如复制文件、下载文件的时候显示进度条。
cpp
#include <QProgressDialog>
QProgressDialog progress("正在处理...", "取消", 0, 100, this);
progress.setWindowTitle("进度");
progress.setWindowModality(Qt::WindowModal); // 窗口模态
for (int i = 0; i <= 100; i++) {
progress.setValue(i); // 设置当前进度
if (progress.wasCanceled()) {
qDebug() << "用户取消了";
break;
}
// 模拟耗时操作(实际项目中这里是你的业务逻辑)
// 注意:实际开发不要用sleep,会卡住界面
// 这里只是演示
}
progress.setValue(100); // 完成
八、自定义对话框
内置的对话框不够用?没关系,我们可以自己做对话框!
8.1 创建自定义对话框
第一步,新建一个QT设计师界面类(或者纯代码写),继承自QDialog。
我们用纯代码来演示:
cpp
// 自定义对话框类
class MyDialog : public QDialog {
Q_OBJECT
public:
MyDialog(QWidget *parent = nullptr) : QDialog(parent) {
setWindowTitle("自定义对话框");
resize(300, 200);
// 布局
QVBoxLayout *layout = new QVBoxLayout(this);
// 输入框
m_edit = new QLineEdit();
m_edit->setPlaceholderText("请输入内容");
layout->addWidget(m_edit);
// 按钮(水平布局)
QHBoxLayout *btnLayout = new QHBoxLayout();
QPushButton *okBtn = new QPushButton("确定");
QPushButton *cancelBtn = new QPushButton("取消");
btnLayout->addStretch();
btnLayout->addWidget(okBtn);
btnLayout->addWidget(cancelBtn);
layout->addLayout(btnLayout);
// 连接信号
connect(okBtn, &QPushButton::clicked, this, &QDialog::accept); // 确定,返回Accepted
connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); // 取消,返回Rejected
}
// 获取输入的内容
QString getText() const {
return m_edit->text();
}
private:
QLineEdit *m_edit;
};
8.2 使用自定义对话框
cpp
// 在主窗口中调用
MyDialog dlg(this);
if (dlg.exec() == QDialog::Accepted) {
QString text = dlg.getText();
qDebug() << "用户输入了:" << text;
} else {
qDebug() << "用户取消了";
}
8.3 对话框返回值
accept()- 确定,返回QDialog::Accepted(值为1)reject()- 取消,返回QDialog::Rejected(值为0)done(int r)- 自定义返回值
你也可以自己定义返回值:
cpp
done(123); // exec()就会返回123
8.4 主窗口和对话框传值
主窗口 → 对话框:通过构造函数或set方法传进去
cpp
// 对话框加一个set方法
void setText(const QString &text) {
m_edit->setText(text);
}
// 主窗口调用
MyDialog dlg(this);
dlg.setText("初始内容"); // 把主窗口的数据传给对话框
dlg.exec();
对话框 → 主窗口:通过get方法拿出来
cpp
// 就是我们上面写的getText()
QString text = dlg.getText();
九、综合实战:记事本的菜单功能
我们来做一个简单的记事本界面,把今天学的对话框都用上:
cpp
#include "mainwindow.h"
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QTextEdit>
#include <QMessageBox>
#include <QInputDialog>
#include <QFileDialog>
#include <QColorDialog>
#include <QFontDialog>
#include <QFile>
#include <QTextStream>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
setWindowTitle("简易记事本");
resize(600, 400);
// 文本编辑区
m_textEdit = new QTextEdit(this);
setCentralWidget(m_textEdit);
// ===== 菜单栏 =====
QMenuBar *menuBar = this->menuBar();
// 文件菜单
QMenu *fileMenu = menuBar->addMenu("文件(&F)");
QAction *openAct = fileMenu->addAction("打开(&O)");
openAct->setShortcut(QKeySequence::Open); // Ctrl+O
connect(openAct, &QAction::triggered, this, &MainWindow::openFile);
QAction *saveAct = fileMenu->addAction("保存(&S)");
saveAct->setShortcut(QKeySequence::Save); // Ctrl+S
connect(saveAct, &QAction::triggered, this, &MainWindow::saveFile);
fileMenu->addSeparator(); // 分隔线
QAction *exitAct = fileMenu->addAction("退出(&X)");
exitAct->setShortcut(QKeySequence::Quit);
connect(exitAct, &QAction::triggered, this, &QWidget::close);
// 编辑菜单
QMenu *editMenu = menuBar->addMenu("编辑(&E)");
QAction *findAct = editMenu->addAction("查找(&F)");
findAct->setShortcut(QKeySequence::Find); // Ctrl+F
connect(findAct, &QAction::triggered, this, &MainWindow::findText);
// 格式菜单
QMenu *formatMenu = menuBar->addMenu("格式(&M)");
QAction *colorAct = formatMenu->addAction("文字颜色(&C)");
connect(colorAct, &QAction::triggered, this, &MainWindow::setColor);
QAction *fontAct = formatMenu->addAction("字体(&F)");
connect(fontAct, &QAction::triggered, this, &MainWindow::setFont);
// 帮助菜单
QMenu *helpMenu = menuBar->addMenu("帮助(&H)");
QAction *aboutAct = helpMenu->addAction("关于(&A)");
connect(aboutAct, &QAction::triggered, this, &MainWindow::showAbout);
}
// 打开文件
void MainWindow::openFile()
{
QString fileName = QFileDialog::getOpenFileName(
this, "打开文件", "", "文本文件 (*.txt);;所有文件 (*.*)"
);
if (fileName.isEmpty()) return;
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox::critical(this, "错误", "无法打开文件!");
return;
}
QTextStream in(&file);
m_textEdit->setText(in.readAll());
file.close();
m_currentFile = fileName;
setWindowTitle(fileName + " - 简易记事本");
}
// 保存文件
void MainWindow::saveFile()
{
if (m_currentFile.isEmpty()) {
// 还没有文件名,弹出保存对话框
m_currentFile = QFileDialog::getSaveFileName(
this, "保存文件", "未命名.txt", "文本文件 (*.txt)"
);
if (m_currentFile.isEmpty()) return;
}
QFile file(m_currentFile);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(this, "错误", "无法保存文件!");
return;
}
QTextStream out(&file);
out << m_textEdit->toPlainText();
file.close();
setWindowTitle(m_currentFile + " - 简易记事本");
QMessageBox::information(this, "提示", "保存成功!");
}
// 查找文字
void MainWindow::findText()
{
bool ok;
QString text = QInputDialog::getText(
this, "查找", "请输入要查找的内容:", QLineEdit::Normal, "", &ok
);
if (!ok || text.isEmpty()) return;
// 查找并选中
if (!m_textEdit->find(text)) {
QMessageBox::information(this, "提示", "找不到 \"" + text + "\"");
}
}
// 设置文字颜色
void MainWindow::setColor()
{
QColor color = QColorDialog::getColor(Qt::black, this, "选择文字颜色");
if (color.isValid()) {
m_textEdit->setTextColor(color);
}
}
// 设置字体
void MainWindow::setFont()
{
bool ok;
QFont font = QFontDialog::getFont(&ok, m_textEdit->font(), this, "选择字体");
if (ok) {
m_textEdit->setFont(font);
}
}
// 关于对话框
void MainWindow::showAbout()
{
QMessageBox::about(
this,
"关于简易记事本",
"简易记事本 v1.0\n\n"
"一个用QT写的简单记事本程序\n"
"作者:零基础学QT"
);
}
运行一下,你就有了一个功能完整的简易记事本!可以打开文件、保存文件、查找文字、设置颜色和字体。
十、今日总结
今天我们学习了QT中的各种对话框,这些都是日常开发中经常用到的!
对话框汇总
| 对话框类 | 用途 | 常用静态方法 |
|---|---|---|
| QMessageBox | 消息提示/询问 | information, warning, critical, question, about |
| QInputDialog | 输入内容 | getText, getInt, getDouble, getItem, getMultiLineText |
| QFileDialog | 选择文件/目录 | getOpenFileName, getSaveFileName, getExistingDirectory |
| QColorDialog | 选择颜色 | getColor |
| QFontDialog | 选择字体 | getFont |
| QProgressDialog | 显示进度 | 直接创建对象,setValue |
| QDialog | 自定义对话框 | 继承它,自己加控件 |
重要概念
- ✅ 模态对话框 :用
exec(),必须关掉才能操作主窗口 - ✅ 非模态对话框 :用
show(),可以和主窗口同时操作 - ✅ 对话框返回值 :
Accepted(确定)、Rejected(取消) - ✅ 传值方式:主窗口→对话框用set方法,对话框→主窗口用get方法
经验分享
- 优先用内置对话框:QT提供的对话框已经很完善了,能满足90%的需求
- 静态方法最方便:大部分对话框都有静态方法,一行代码就能调用
- 文件过滤器要写好:让用户更容易找到想要的文件
- 自定义对话框继承QDialog:不要自己从零写,继承QDialog省很多事
- 模态 vs 非模态:重要操作、必须等用户回复的用模态;辅助工具用非模态
十一、明日预告
明天我们将学习菜单栏、工具栏、状态栏(QMenuBar、QToolBar、QStatusBar)。
一个完整的桌面应用,通常都有:
- 顶部的菜单栏(文件、编辑、帮助...)
- 工具栏(一排图标按钮)
- 底部的状态栏(显示状态信息)
这些都是QMainWindow自带的功能,我们会学习怎么添加菜单、怎么加工具栏按钮、怎么在状态栏显示信息。
学会这些,你就能做出像模像样的桌面软件了!
📝 学习建议:对话框是QT开发中非常实用的内容,建议每个对话框都自己试一遍。
练习建议:
- 把今天的简易记事本代码敲一遍
- 试试加一个"另存为"功能
- 试试加一个"替换"功能(用QInputDialog输入要替换的内容)
- 自己设计一个登录对话框(用户名+密码)
对话框掌握了,和用户交互就不成问题了!明天见,继续加油!💪