Day 3

QMainWindow / 对话框 QDialog / 布局管理器 / 常用控件

C++/Qt 方向实训 · 第 3 / 4 个讲授日

  • 上午(08:30–11:00 讲 / 11:00–12:00 练):QMainWindow · 对话框 QDialog
  • 下午(13:30–16:00 讲 / 16:00–17:00 作业):布局管理器 · 常用控件 · QSS 美化

今天的主线:把昨天的计算器升级成"正经软件"——主窗口骨架 + 对话框交互 + 布局讲透 + 美化。

上午 · 讲授 08:30–11:00

QMainWindow / 对话框 QDialog

QMainWindow:标准桌面软件的骨架

核心概念

  • QMainWindow 不是"大号 QWidget":它有固定的区域布局协议——菜单栏 / 工具栏 / 状态栏 / 停靠窗(dock)各就其位,中心部件必须 setCentralWidget() 显式安放;菜单项和工具栏按钮的统一抽象是 QAction(一个动作, 多处复用)。

常见的坑

  • 直接往 QMainWindow 上摆控件而不设中心部件——布局行为不可预期;
  • QAction 显示出来 ≠ 生效:忘了 connect 到槽, 就是"菜单点了没反应"。

出处:p03/ch05/central_widget.cpp · dock_widget.cpp

QDialog:模态与非模态

核心概念

  • 模态 exec():阻塞等用户给结果,返回值就是用户的选择 (Accepted/Rejected);非模态 show():立即返回,窗口独立存活 ——所以对话框对象必须活过当前函数作用域(堆 + parent,或 WA_DeleteOnClose 自清理)。
  • 标准对话框拿来就用:QMessageBox(提示/确认)、QFileDialog(选文件)。

常见的坑(昨天的所有权坑第三次出现!)

  • 非模态对话框建在栈上show() 完函数一返回就析构——窗口一闪而过。 p03/ch06 的三个 modeless 版本(栈/堆/DeleteOnClose)就是这个坑的对照教材。

出处:p03/ch06/modal_dialog.cpp · modeless_dialog_stack.cpp · modeless_dialog_heap.cpp · modeless_dialog_deleteonclose.cpp

标准对话框速览


auto ret = QMessageBox::question(this, "确认", "真的要删除吗?");
if (ret == QMessageBox::Yes) { /* ... */ }

QString path = QFileDialog::getOpenFileName(this, "选择文件", "", "*.json");
if (!path.isEmpty()) { /* ... */ }   // 用户可能点取消:必须处理空返回
    

常见的坑

  • 不处理"用户点了取消"(空路径/Rejected)就直接往下用——健壮性问题的高发点。

出处:p03/ch06/message_box_question.cpp · message_box_custom.cpp · file_dialog.cpp

上午 · 课堂练习 11:00–12:00(工程师指导、答疑)

动手:计算器主窗口化

任务卡 1 · 给计算器套上 QMainWindow

目标
把昨天的计算器改造为 QMainWindow 应用:加菜单「帮助→关于」弹 QMessageBox;加一个「历史」停靠窗(可先放空 QLabel)
验收标准
计算器功能不回退;菜单动作有响应;停靠窗可拖动/收起
基础知识 · 参考
p03/ch05/central_widget.cpp · dock_widget.cpp · p03/ch06/message_box_question.cpp

下午 · 讲授 13:30–16:00

布局管理器 / 常用控件 / QSS 美化

布局管理器(回收昨天的脚手架)

核心概念

  • 布局管理器接管子控件的位置/大小计算,随窗口缩放自动重排——昨天计算器里"先用后学" 的 QGridLayout 今天讲透:QHBox/QVBox/QGrid 三兄弟 + 嵌套组合 + 伸缩因子 addStretch();布局对象同样遵循 QObject 父子所有权。

常见的坑

  • 同一控件不能属于两个布局;
  • 布局设置后又用 setGeometry()/move() 手动改位置—— 会被下次布局刷新覆盖,看起来"设置没生效"。

出处:p03/ch08/custom_widget.cpp

常用控件 + 资源系统 .qrc

核心概念

  • QLabel 一个控件三种形态:纯文本 / 富文本 HTML / 图片(QPixmap)/ 动图(QMovie);输入靠 QLineEdit,按钮族 QPushButton/QRadioButton/QCheckBox。
  • :/... 路径是 Qt 资源系统:资源编译期打包进可执行文件,运行时不依赖 外部文件——发布不用带一堆散图。

常见的坑

  • .qrc 里的路径与代码引用不一致:运行时静默失败(图不显示), 不报编译错误;忘接 CMake 的 AUTORCC/qt5_add_resources 资源系统不生效。

出处:p03/ch08/label_text_html.cpp · label_pixmap.cpp · label_movie.cpp

QSS 界面美化

QPushButton#okButton { background-color: #2f855a; border-radius: 6px; }
QPushButton#okButton:hover { background-color: #276749; }

核心概念

  • 语法脱胎于 CSS:类型选择器 / ID 选择器(#objectName)/ 伪状态 (:hover :pressed)+ 层叠继承——作用对象是 QWidget 树而非 DOM; "长什么样"与"做什么"分离,改样式不碰逻辑。

常见的坑

  • ID 选择器必须先 setObjectName()
  • setStyleSheet() 会级联影响所有子控件——范围失控是最容易踩的坑, 样式尽量写窄(带选择器),不要裸写属性。

出处:examples/qss_styling/qt_qss_styling.cppREADME

下午 · 课堂作业 16:00–17:00(工程师答疑)

作业:计算器美化升级

任务卡 2 · 用 QSS 美化计算器

目标
数字键/运算键/等号键用 QSS 区分颜色;整体布局改为随窗口缩放自适应
验收标准
至少 2 类按钮有不同 background-color;至少 1 个按钮有 :hover:pressed 效果;拉伸窗口按钮跟着重排
基础知识 · 参考
examples/qss_styling/ · p03/ch08/custom_widget.cpp

当日产出验证

验收

现场演示升级后的计算器:主窗口(菜单/停靠窗)+ QSS 配色 + 缩放自适应,功能不回退。

返回目录 · ← 上一天 · 下一天 →