解码Qt 对话框与文件操作
Qt 对话框(QDialog)
对话框是GUI程序中实现短期交互、功能配置的顶层/子窗口,Qt中通过QDialog类实现(继承自QWidget)。
QDialog的parent参数特殊意义:parent = nullptr:对话框为顶层窗口,任务栏有独立位置;parent != nullptr:对话框为父组件的子对话框,默认显示在父组件中心,共享父组件的任务栏位置。
对话框分类
对话框核心分为模态对话框和非模态对话框,核心区别是是否阻塞用户对其他窗口的操作。
模态对话框
定义:显示时阻塞用户输入,其他窗口无法获取焦点,直到对话框关闭。
模态对话框分两种级别:
- 应用程序级模态:阻塞整个应用的所有窗口(最常用);
- 窗口级模态:仅阻塞关联的父窗口,其他窗口可正常操作。
| 显示方式 | 模态级别 | 阻塞范围 | 返回值 | 关闭方式 |
|---|---|---|---|---|
exec() |
应用级 | 整个应用 | QDialog::Accepted(确定)/QDialog::Rejected(取消) |
accept()/reject() |
open() |
窗口级 | 仅父窗口 | 无(通过信号finished(int result)获取结果) |
accept()/reject() |
示例(应用级模态对话框):

void MainWindow::showModalDialog()
{
QDialog dlg(this); // 父窗口为MainWindow,子对话框
dlg.setWindowTitle("应用级模态对话框");
dlg.resize(300, 100);
// 添加确定按钮
QPushButton *okBtn = new QPushButton("确定", &dlg);
QObject::connect(okBtn, &QPushButton::clicked, &dlg, &QDialog::accept);
// 添加取消按钮
QPushButton *cancelBtn = new QPushButton("取消", &dlg);
QObject::connect(cancelBtn, &QPushButton::clicked, &dlg, &QDialog::reject);
// 布局管理
QHBoxLayout *layout = new QHBoxLayout(&dlg);
layout->addWidget(okBtn);
layout->addWidget(cancelBtn);
/**
* exec():显示应用级模态对话框,阻塞直到对话框关闭
* @return int 关闭后返回QDialog::Accepted(1)或QDialog::Rejected(0)
* @note 执行exec()时,当前线程阻塞,但Qt的事件循环仍在运行(界面不卡死)
*/
int ret = dlg.exec();
if (ret == QDialog::Accepted) {
qDebug() << "用户点击了确定";
} else if (ret == QDialog::Rejected) {
qDebug() << "用户点击了取消";
}
}
非模态对话框
定义:显示时不阻塞程序执行,用户可同时操作主窗口/其他窗口(如记事本的“查找”对话框)。
- 显示方式:调用
show()(非阻塞,立即返回); - 内存注意:非模态对话框若为局部对象,函数结束后会被销毁,需用
new创建(可结合setAttribute(Qt::WA_DeleteOnClose)关闭时自动释放内存)。
示例(非模态对话框):

void MainWindow::showNonModalDialog()
{
/**
* 非模态对话框需动态创建,避免局部对象销毁导致窗口消失
* setAttribute(Qt::WA_DeleteOnClose):对话框关闭时自动释放内存,防止内存泄漏
*/
QDialog *dlg = new QDialog(this);
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->setWindowTitle("非模态对话框");
dlg->resize(300, 100);
QPushButton *btn = new QPushButton("关闭", dlg);
QObject::connect(btn, &QPushButton::clicked, dlg, &QDialog::close);
QHBoxLayout *layout = new QHBoxLayout(dlg);
layout->addWidget(btn);
/**
* show():显示非模态对话框,立即返回,不阻塞程序执行
* @note 非模态对话框不会阻塞事件循环,用户可同时操作主窗口
*/
dlg->show();
}
标准对话框(Qt内置)
Qt提供一系列封装好的标准对话框,无需自定义,直接调用即可实现常见交互。
文件对话框(QFileDialog)
用于选择文件/目录路径(打开/保存文件),支持两种使用方式:创建对象、调用静态函数(推荐)。
方式1:创建QFileDialog对象

void MainWindow::openFileDialogByObj()
{
QFileDialog fileDlg(this);
/**
* QFileDialog构造函数:QFileDialog(QWidget *parent = nullptr, const QString &caption = QString(), const QString &directory = QString(), const QString &filter = QString())
* @param parent 父窗口,决定对话框的模态范围和显示位置
* @param caption 对话框标题(默认空)
* @param directory 初始打开的目录(默认当前程序目录)
* @param filter 文件过滤器,格式:"文本文件 (*.txt);;图片文件 (*.png *.jpg)"
*/
fileDlg.setWindowTitle("选择文件(对象方式)");
fileDlg.setDirectory("E:\\Project\\QT"); // 设置初始目录
fileDlg.setNameFilter("文本文件 (*.txt);;所有文件 (*.*)"); // 过滤仅显示txt和所有文件
/**
* exec():模态显示文件对话框
* fileSelected信号:用户选择文件并确认后触发,参数为选中的文件绝对路径
*/
QObject::connect(&fileDlg, &QFileDialog::fileSelected, [](const QString &fileName) {
qDebug() << "选中的文件路径:" << fileName;
});
fileDlg.exec();
}
方式2:调用静态函数(推荐)

void MainWindow::openFileDialogByStatic()
{
/**
* QFileDialog::getOpenFileName:打开“选择单个文件”对话框(应用级模态)
* @param parent 父窗口
* @param caption 对话框标题(默认"Open File")
* @param dir 初始目录(默认当前程序目录)
* @param filter 文件过滤器(默认空)
* @param selectedFilter 输出参数,返回用户选中的过滤器(可选)
* @param options 对话框选项(如QFileDialog::DontUseNativeDialog,可选)
* @return QString 选中的文件绝对路径;用户取消则返回空字符串
*/
QString fileName = QFileDialog::getOpenFileName(
this, // parent
"选择文件(静态函数)", // caption
"E:\\Project\\QT", // dir
"文本文件 (*.txt);;所有文件 (*.*)" // filter
);
if (!fileName.isEmpty()) {
qDebug() << "选中的文件路径:" << fileName;
} else {
qDebug() << "用户取消了选择";
}
// 其他常用静态函数:
// getOpenFileNames():选择多个文件,返回QStringList
// getSaveFileName():选择保存文件路径,自动提示覆盖已存在文件
// getExistingDirectory():选择目录路径,返回目录绝对路径
}
颜色对话框(QColorDialog)
用于选择颜色,返回QColor对象,可设置控件的前景/背景色。

void Widget::on_pushButton_clicked()
{
/**
* QColorDialog::getColor:打开颜色选择对话框
* @param initial 初始颜色(默认白色)
* @param parent 父窗口
* @param title 对话框标题(默认"Select Color")
* @param options 对话框选项(可选)
* @return QColor 选中的颜色;用户取消则返回无效颜色(可通过isValid()判断)
*/
QColor color = QColorDialog::getColor(
Qt::white, // 初始颜色
this, // parent
"选择背景颜色" // title
);
if (color.isValid()) { // 判断是否选中有效颜色(用户未取消)
// 设置标签背景色:StyleSheet语法 "控件{属性:值}"
ui->label->setStyleSheet(QString("QLabel{background-color:%1;}").arg(color.name()));
}
}
输入对话框(QInputDialog)
用于获取用户输入的文本、数字、下拉选项等,常用静态函数getText()/getInt()/getDouble()。

void Widget::on_pushButton_clicked()
{
/**
* QInputDialog::getText:打开文本输入对话框
* @param parent 父窗口
* @param title 对话框标题
* @param label 输入提示文本
* @param echoMode 输入框模式(QLineEdit::Normal/Password等)
* @param text 初始输入文本(默认空)
* @param ok 输出参数,返回true表示用户确认,false表示取消(可选)
* @param flags 窗口标志(可选)
* @return QString 用户输入的文本;取消则返回空字符串
*/
bool ok;
QString inputText = QInputDialog::getText(
this, // parent
"密码输入", // title
"请输入密码:", // label
QLineEdit::Password,// 密码模式(输入内容隐藏)
"", // 初始文本
&ok // 输出参数:是否确认
);
if (ok && !inputText.isEmpty()) {
ui->label->setText(QString("输入的密码:%1").arg(inputText));
} else {
ui->label->setText("用户取消了输入或输入为空");
}
// 其他常用静态函数:
// getInt():输入整数,可指定范围(min/max)和步长
// getDouble():输入浮点数,可指定范围和小数位数
// getItem():下拉选项选择,返回选中的选项文本
}
字体对话框(QFontDialog)
用于选择字体(字号、样式、粗细等),返回QFont对象。

void Widget::on_pushButton_clicked()
{
/**
* QFontDialog::getFont:打开字体选择对话框
* @param ok 输出参数,返回true表示用户确认,false表示取消
* @param initial 初始字体(默认应用程序字体)
* @param parent 父窗口
* @param title 对话框标题(默认"Select Font")
* @param options 对话框选项(可选)
* @return QFont 选中的字体;取消则返回初始字体(需通过ok判断是否有效)
*/
bool ok;
QFont font = QFontDialog::getFont(
&ok, // 输出参数:是否确认
ui->label->font(), // 初始字体(使用标签当前字体)
this, // parent
"选择字体" // title
);
if (ok) { // 仅当用户确认时,才设置字体
ui->label->setFont(font);
}
}
消息对话框(QMessageBox)
用于提示信息、询问确认(如删除确认),模态显示,返回用户点击的按钮类型。

void Widget::on_pushButton_clicked()
{
/**
* QMessageBox::warning:打开警告类型消息框(其他类型:info/critical/question)
* @param parent 父窗口
* @param title 对话框标题
* @param text 主要提示文本
* @param buttons 显示的按钮(默认Ok),如QMessageBox::Yes|QMessageBox::No
* @param defaultButton 默认选中的按钮(可选)
* @return QMessageBox::StandardButton 用户点击的按钮类型;取消则返回QMessageBox::NoButton
*/
QMessageBox::StandardButton ret = QMessageBox::warning(
this, // parent
"删除确认", // title
"确定要删除该文件吗?", // text
QMessageBox::Yes | QMessageBox::No, // 显示“是”和“否”按钮
QMessageBox::No // 默认选中“否”按钮
);
if (ret == QMessageBox::Yes) {
qDebug() << "用户确认删除";
// 执行删除逻辑
} else if (ret == QMessageBox::No) {
qDebug() << "用户取消删除";
}
// 其他常用静态函数:
// QMessageBox::information():提示普通信息(如操作成功)
// QMessageBox::critical():提示错误信息(如文件打开失败)
// QMessageBox::question():询问用户(如是否保存更改)
}
自定义对话框
当标准对话框无法满足需求时,可自定义对话框(继承QDialog或直接创建QDialog对象)。
示例(自定义对话框,继承QDialog):

// 自定义对话框类头文件(CustomDialog.h)
#include <QDialog>
#include <QPushButton>
#include <QHBoxLayout>
class CustomDialog : public QDialog
{
Q_OBJECT
public:
explicit CustomDialog(QWidget *parent = nullptr) : QDialog(parent) {
setWindowTitle("自定义对话框");
resize(300, 100);
// 创建按钮
QPushButton *okBtn = new QPushButton("确定", this);
QPushButton *cancelBtn = new QPushButton("取消", this);
// 布局
QHBoxLayout *layout = new QHBoxLayout(this);
layout->addWidget(okBtn);
layout->addWidget(cancelBtn);
// 信号槽:点击按钮关闭对话框
connect(okBtn, &QPushButton::clicked, this, &QDialog::accept);
connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject);
}
};
// 主窗口中调用
void MainWindow::openCustomDialog()
{
CustomDialog dlg(this);
/**
* exec():模态显示自定义对话框
* @return int QDialog::Accepted(确定)/QDialog::Rejected(取消)
*/
int ret = dlg.exec();
if (ret == QDialog::Accepted) {
qDebug() << "用户点击了自定义对话框的确定";
} else {
qDebug() << "用户点击了自定义对话框的取消";
}
}
Qt 文件操作
Qt提供QFile(文件读写)、QDir(目录操作)、QTextStream(文本文件便捷读写)等类,简化文件/目录操作。
QFile(文件基础操作)
QFile是Qt文件IO的核心类,支持文件的打开、关闭、读写、删除等操作。
打开/关闭文件
void MainWindow::fileOpenClose()
{
QFile file("example.txt"); // 关联文件(相对路径:程序当前目录;绝对路径:如"C:/test/example.txt")
/**
* QFile::open:打开文件
* @param mode 打开模式(组合使用,如ReadOnly | Text)
* - QIODevice::ReadOnly:只读模式(文件不存在则打开失败)
* - QIODevice::WriteOnly:只写模式(文件不存在则创建;存在则清空内容)
* - QIODevice::ReadWrite:读写模式
* - QIODevice::Append:追加模式(WriteOnly/ReadWrite时,写入内容追加到文件末尾)
* - QIODevice::Text:文本模式(自动转换换行符:Windows \\r\\n ↔ Linux \\n)
* @return bool 打开成功返回true,失败返回false(可通过error()获取错误码)
*/
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "文件打开成功";
// 操作完成后关闭文件(必须调用,释放文件句柄)
file.close();
} else {
qDebug() << "文件打开失败:" << file.errorString(); // 输出错误信息
}
}

读写文件
void MainWindow::fileReadWrite()
{
// 1. 写入文件(WriteOnly + Text)
QFile writeFile("example.txt");
if (writeFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
/**
* QFile::write:写入数据
* @param data 要写入的字节数据(QByteArray/char*)
* @return qint64 实际写入的字节数;失败返回-1
*/
QString writeContent = "Hello Qt!\n你好 Qt!"; // 用QString保证中文编码正确
qint64 writeBytes = writeFile.write(writeContent.toUtf8()); // 转为UTF-8字节写入
if (writeBytes > 0) {
qDebug() << "写入成功,字节数:" << writeBytes;
}
writeFile.close();
}
// 2. 读取文件(ReadOnly + Text)
QFile readFile("example.txt");
if (readFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
/**
* QFile::read:读取指定字节数;readAll():读取全部内容
* @param maxSize 最大读取字节数(默认-1,读取全部)
* @return QByteArray 读取的内容;失败返回空
*/
QByteArray allData = readFile.readAll();
// 方案1:直接转QString(推荐,指定UTF-8编码)
qDebug() << "文件全部内容(中文正常显示):" << QString::fromUtf8(allData);
readFile.seek(0);
// 逐行读取:转为QString显示中文
while (!readFile.atEnd()) {
QByteArray lineData = readFile.readLine();
// 关键:fromUtf8 解析字节为UTF-8字符串,trimmed去换行/空格
QString lineStr = QString::fromUtf8(lineData).trimmed();
qDebug() << "逐行读取(中文正常):" << lineStr;
}
readFile.close();
}
}

获取文件信息(QFileInfo)
QFileInfo封装文件的元信息(文件名、路径、大小、修改时间等)。
void MainWindow::fileInfo()
{
QFileInfo fileInfo("example.txt");
if (fileInfo.exists()) { // 判断文件是否存在
qDebug() << "文件名:" << fileInfo.fileName(); // 示例:example.txt
qDebug() << "绝对路径:" << fileInfo.absoluteFilePath(); // 示例:C:/build/example.txt
qDebug() << "文件大小:" << fileInfo.size() << "字节"; // 字节数
qDebug() << "创建时间:" << fileInfo.birthTime().toString("yyyy-MM-dd hh:mm:ss");
qDebug() << "修改时间:" << fileInfo.lastModified().toString("yyyy-MM-dd hh:mm:ss");
qDebug() << "是否为文件:" << fileInfo.isFile(); // true(区分文件/目录)
qDebug() << "是否为目录:" << fileInfo.isDir(); // false
} else {
qDebug() << "文件不存在";
}
}

QDir(目录操作)
QDir用于目录的遍历、创建、删除、重命名等操作,支持绝对/相对路径。
枚举目录内容
void MainWindow::dirEnum()
{
QDir dir("./"); // 关联当前目录(绝对路径:如"C:/test")
/**
* QDir::entryList:获取目录下的文件/子目录列表
* @param filters 过滤规则(组合使用)
* - QDir::Files:仅显示文件
* - QDir::Dirs:仅显示子目录(包含"."当前目录、".."上级目录)
* - QDir::NoDotAndDotDot:排除"."和".."
* - QDir::Hidden:显示隐藏文件/目录
* @param sort 排序规则(如QDir::Name:按名称排序)
* @return QStringList 符合条件的文件/目录名称列表
*/
// 获取目录下所有文件(排除隐藏文件)
QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
qDebug() << "目录下的文件:" << files;
// 获取目录下所有子目录(排除.和..)
QStringList subDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
qDebug() << "目录下的子目录:" << subDirs;
}

创建/删除目录
void MainWindow::dirCreateDelete()
{
QDir dir("./");
// 1. 创建目录:mkpath() 递归创建(如"test/subdir",父目录不存在则自动创建)
QString newDir = "test/subdir";
/**
* QDir::mkpath:递归创建目录
* @param path 要创建的目录路径
* @return bool 创建成功(或已存在)返回true,失败返回false
*/
if (dir.mkpath(newDir)) {
qDebug() << "目录创建成功:" << newDir;
} else {
qDebug() << "目录创建失败:" << newDir;
}
// 2. 删除目录:rmdir() 删除空目录;rmdir()仅删除最后一级空目录
/**
* QDir::rmdir:删除空目录
* @param dirName 要删除的目录名称
* @return bool 删除成功返回true,失败返回false(目录非空/不存在则失败)
*/
if (dir.rmdir("test/subdir")) { // 先删除子目录
qDebug() << "子目录删除成功";
if (dir.rmdir("test")) { // 再删除空的父目录
qDebug() << "父目录删除成功";
}
} else {
qDebug() << "目录删除失败(目录非空或不存在)";
}
// 注:删除非空目录需先遍历删除所有文件/子目录,或使用QDir::removeRecursively()(Qt 5.15+)
// dir.removeRecursively("test"); // 递归删除目录及所有内容
}

QTextStream(文本文件便捷读写)
QTextStream封装了文本文件的读写逻辑,支持字符串、数值、换行符等便捷操作,无需手动处理字节转换。
读取文本文件
void MainWindow::textStreamRead()
{
QFile file("example.txt");
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
/**
* QTextStream:文本流对象,关联QFile
* @param device 关联的IO设备(如QFile)
* @note 文本流自动处理编码(默认UTF-8,可通过setCodec()设置,如setCodec("GBK"))
*/
QTextStream in(&file);
in.setCodec("UTF-8"); // 设置读取编码(解决中文乱码)
/**
* QTextStream::readLine:读取一行文本(自动去除换行符)
* @return QString 读取的一行内容;到末尾返回空字符串
* @note atEnd():判断是否到文件末尾
*/
while (!in.atEnd()) {
QString line = in.readLine();
qDebug() << "文本流逐行读取:" << line;
}
file.close();
}
}

写入文本文件
void MainWindow::textStreamWrite()
{
QFile file("example.txt");
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out(&file);
out.setCodec("UTF-8"); // 设置写入编码
/**
* QTextStream::operator<<:写入文本(支持字符串、数值、endl等)
* @param data 要写入的内容(QString/int/double等)
* @return QTextStream& 流对象本身,支持链式调用
* @note endl:插入换行符并刷新缓冲区(确保内容立即写入文件)
*/
out << QByteArray("Qt 文本流写入") << endl;
out << QByteArray("整数:") << 123 << QByteArray(" 浮点数:") << 3.14 << endl;
out << QByteArray("中文测试:你好 Qt!") << endl;
file.close();
}
}

常见注意事项
- 路径问题:Windows路径用
/或\\(如C:/test.txt或C:\\test.txt),Linux用/; - 编码问题:
QTextStream默认UTF-8,读取GBK文件需设置setCodec("GBK"); - 大文件读写:避免
readAll(),改用readLine()或read(n)分块读取; - 内存管理:非模态对话框、动态创建的文件/目录对象需注意释放,避免内存泄漏;
- 权限问题:写入系统目录(如C:/Windows)需管理员权限,否则打开失败。

浙公网安备 33010602011771号