第九章 对话框系统:与用户对话的艺术
对话框,说白了就是程序跟用户「聊天」的窗口。你点个「打开文件」,弹个框让你选;你点个「关于」,弹个框告诉你版本信息。这些看似简单的交互,背后都是 QDialog 家族在干活。
我个人习惯把对话框分成两类:一类是「通知型」,比如告诉用户「保存成功」;另一类是「交互型」,比如让用户选颜色、选字体。今天咱们就把 Qt 里最常用的几个对话框挨个捋一遍。
本章核心:掌握 QDialog 的基类特性,熟练使用 5 大标准对话框(消息框、文件框、颜色框、字体框、输入框),并能自定义对话框满足特殊需求。
9.1 QDialog:对话框的基石
QDialog 是所有对话框的爸爸。它跟 QWidget 最大的区别是什么?嗯,关键在于它的执行模式。
对话框有两种模式:
- 模态对话框:弹出来以后,你没法操作主窗口。必须关掉它才能继续。用
exec()启动。 - 非模态对话框:弹出来以后,两边都能操作。用
show()启动。
我在项目中遇到过一个问题:有个同事把耗时操作放在模态对话框里,结果界面卡死了。后来改成非模态 + 后台线程才解决。你想想看,对话框只是交互工具,别让它干重活。
// 模态对话框
QDialog *dlg = new QDialog(this);
dlg->setModal(true); // 或者直接 dlg->exec()
dlg->exec();
// 非模态对话框
QDialog *dlg = new QDialog(this);
dlg->setAttribute(Qt::WA_DeleteOnClose); // 关闭时自动释放
dlg->show();
我的习惯:非模态对话框一定要设置 WA_DeleteOnClose,否则内存泄漏等着你。我曾经因为这个坑,排查了一下午。
9.2 QMessageBox:最常用的消息通知
QMessageBox 可能是你用得最多的对话框。提示信息、警告、错误、提问……它都能干。
Qt 提供了几个静态方法,一行代码就能弹出对话框:
// 信息提示
QMessageBox::information(this, "标题", "文件保存成功!");
// 警告
QMessageBox::warning(this, "警告", "磁盘空间不足!");
// 错误
QMessageBox::critical(this, "错误", "无法打开文件!");
// 提问(带返回值)
int ret = QMessageBox::question(this, "确认", "确定要删除吗?",
QMessageBox::Yes | QMessageBox::No);
if (ret == QMessageBox::Yes) {
// 执行删除
}
你可能会问:这些静态方法够用吗?说实话,大部分场景够了。但如果你需要自定义按钮文字、图标,那就得自己构造 QMessageBox 对象了。
避坑指南:我曾经在循环里调用 QMessageBox::information(),结果弹了一百多个框,用户差点砸电脑。记住:不要在频繁调用的代码路径里弹对话框。
9.3 QFileDialog:文件选择的标准方案
文件对话框,每个桌面应用几乎都离不开。Qt 的 QFileDialog 封装得很好,支持打开、保存、选择目录等多种模式。
// 打开单个文件
QString filePath = QFileDialog::getOpenFileName(
this, "选择图片", "/home/user",
"图片文件 (*.png *.jpg *.bmp);;所有文件 (*)");
// 打开多个文件
QStringList files = QFileDialog::getOpenFileNames(
this, "选择多个文件", "/home/user",
"文本文件 (*.txt *.csv)");
// 保存文件
QString savePath = QFileDialog::getSaveFileName(
this, "保存文件", "/home/user/untitled.txt",
"文本文件 (*.txt)");
// 选择目录
QString dir = QFileDialog::getExistingDirectory(
this, "选择目录", "/home/user");
注意那个过滤器格式:"描述 (*.ext1 *.ext2)"。多个过滤器用两个分号隔开。我刚开始写的时候老记错,后来干脆写了个工具函数封装起来。
小技巧:如果你想让对话框记住上次打开的路径,可以用 QSettings 保存路径。用户体验会好很多。
9.4 QColorDialog:颜色选择器
颜色对话框,说白了就是让用户挑颜色。Qt 默认提供了一个漂亮的色盘,支持 RGB、HSV 等多种模式。
QColor color = QColorDialog::getColor(Qt::white, this, "选择背景色");
if (color.isValid()) {
// 用户选择了颜色
ui->widget->setStyleSheet(
QString("background-color: %1").arg(color.name()));
}
这里有个细节:getColor() 返回的 QColor 可能无效(用户点了取消)。一定要用 isValid() 检查一下。我曾经偷懒没检查,结果程序直接崩了。
如果你想让用户只能选基本色,可以设置选项:
QColorDialog dialog(this);
dialog.setOption(QColorDialog::ShowAlphaChannel); // 显示透明度
dialog.setOption(QColorDialog::NoButtons); // 隐藏确定/取消按钮
dialog.exec();
9.5 QFontDialog:字体选择器
字体对话框跟颜色对话框很像,只不过选的是字体。它返回一个 QFont 对象,包含字体名称、大小、粗体、斜体等信息。
bool ok;
QFont font = QFontDialog::getFont(&ok, QFont("微软雅黑", 12), this);
if (ok) {
// 用户确认了选择
ui->textEdit->setFont(font);
}
注意那个 &ok 参数。它用来判断用户是点了「确定」还是「取消」。嗯,这个设计比 QColorDialog 的 isValid() 更直观一些。
经验之谈:字体对话框默认会列出系统所有字体。如果你只想显示等宽字体(比如给代码编辑器用),可以设置 QFontDialog::MonospacedFonts 选项。
9.6 QInputDialog:轻量级输入
有时候你只需要用户输入一个简单的值——一个数字、一段文字、或者从列表里选一项。这时候用 QInputDialog 最合适,省得自己写对话框。
// 输入文本
bool ok;
QString text = QInputDialog::getText(
this, "输入姓名", "请输入您的姓名:",
QLineEdit::Normal, "张三", &ok);
if (ok && !text.isEmpty()) {
// 处理输入
}
// 输入整数
int value = QInputDialog::getInt(
this, "设置年龄", "请输入年龄:",
25, 0, 150, 1, &ok);
// 从列表选择
QStringList items = {"红", "绿", "蓝"};
QString item = QInputDialog::getItem(
this, "选择颜色", "请选择一种颜色:",
items, 0, false, &ok);
QInputDialog 有 5 种输入模式:文本、整数、浮点数、列表、多行文本。每种都有对应的静态方法。我个人觉得 getItem() 最实用,下拉选择比手动输入更防错。
注意:输入对话框默认没有输入验证。比如 getInt() 虽然能限制范围,但用户还是可以输入非法字符。如果你需要严格验证,建议自己写一个 QDialog 子类。
9.7 自定义对话框:当标准控件不够用时
标准对话框虽然方便,但总有满足不了需求的时候。比如你要做一个「批量导入设置」对话框,里面有表格、有复选框、有进度条……这时候就得自己动手了。
自定义对话框的步骤很简单:
- 新建一个类,继承 QDialog
- 在构造函数里布局控件
- 添加必要的信号/槽
- 设置对话框大小、标题、模态属性
class BatchImportDialog : public QDialog {
Q_OBJECT
public:
explicit BatchImportDialog(QWidget *parent = nullptr);
QStringList selectedFiles() const;
private:
QListWidget *fileList;
QCheckBox *overwriteCheck;
QPushButton *importBtn;
QPushButton *cancelBtn;
};
BatchImportDialog::BatchImportDialog(QWidget *parent)
: QDialog(parent)
{
setWindowTitle("批量导入");
setModal(true);
resize(400, 300);
// 布局代码省略...
}
自定义对话框的核心是:你想让用户输入什么,就提供什么控件。最后通过公有方法把数据传出去。别把逻辑写在对话框里,对话框只负责交互。
知识体系总览
下面这张图总结了本章的对话框体系。你可以看到,所有对话框都继承自 QDialog,而 QDialog 又继承自 QWidget。标准对话框覆盖了大部分常见需求,自定义对话框则填补了剩下的空白。
从这张图可以看得很清楚:标准对话框覆盖了 80% 的常见需求,剩下的 20% 靠自定义对话框解决。我建议你先把标准对话框用熟,遇到特殊需求再考虑自定义。
最后说一句:对话框的设计原则是「让用户少思考」。能用下拉列表就别让用户打字,能点选就别让用户输入。好的对话框,用户闭着眼睛都能操作。
公众号:蓝海资料掘金营,微信deep3321