Files
张宗平 05a685c952 Day3 教学示例:增强版计算器接入 + QMainWindow/QSS 两版参考实现
- calculator_designer_ext(Day2 增强版:表达式求值 + 括号,递归下降解析器)接入 cmake
- calculator_mainwindow(Day3 上午):增强版计算器装进 QMainWindow,
  菜单/状态栏/历史停靠窗,纯代码 + 显式 connect,与 mainwindow_showcase 形成坑卡对照
- calculator_mainwindow_qss(Day3 下午):上午版 + QSS 双主题美化(按键分色/伪状态/深浅切换)
- 验证 mainwindow_showcase(QMainWindow 六大组件综合演示,.ui + .qrc)
- OUTLINE_4DAY.md / ASSIGNMENTS.md Day3 衔接增强版起点 + 参考实现指引
- 补提交 Day2 calculator/ 与 calculator_designer/ 参考实现(CMakeLists 已引用)
- 全量构建 28/28,4 目标离屏自测退出码 0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 22:59:05 +08:00

60 lines
3.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 简易计算器 —— Qt Designer 表单对照版
> 对应教案 [`OUTLINE_4DAY.md`](../../OUTLINE_4DAY.md) Day2 下午「项目案例:简易
> 计算器」。与 [`../calculator/`](../calculator/README.md)(纯代码 `QGridLayout`
> 版)对照阅读:**界面搭建方式换了,业务逻辑一字不差**——`onDigit`/`onOperator`/
> `onEquals`/`onClear`/`onBackspace`/`compute` 全部照搬。手工维护,非生成产物。
## 与代码版的唯一区别:界面从哪来
| | 代码版 `qt_calculator.cpp` | Designer 版 `qt_calculator_designer.cpp` |
|---|---|---|
| 控件树+布局 | `buildKeypad()` 手写 `new QPushButton` + `QGridLayout::addWidget` | `calculator_designer.ui`Designer 表单 XML+ `uic` 编译期生成 `ui_calculator_designer.h` + `setupUi(this)` 一次建好 |
| 找控件 | 局部变量/成员指针 | `ui->btn7``ui->display` ……(objectName 对应成员名) |
| 构建开关 | `AUTOMOC ON` | `AUTOMOC ON` **+ `AUTOUIC ON`**CMake 自动跑 `uic` |
| 业务逻辑 | 状态机 | 完全相同 |
## ★ 新增知识点:Designer 表单的「自动连接」
`ui->setupUi(this)` 内部会调用 `QMetaObject::connectSlotsByName(this)`:只要
类里有名为 `on_<objectName>_<signal>()` 的槽(比如 `on_btnClear_clicked()`),
Qt 会**自动**把表单里 `objectName``btnClear` 的控件的 `clicked()` 信号连上去,
不需要手写 `connect()`。这是信号槽的第三种写法(前两种见 `../calculator/`)。
**本示例故意不用这个自动连接**,全部改成显式 `connect()`——原因是当天的坑卡:
- 坑:表单里把按钮 `objectName``btnClear` 改成 `btnReset``on_btnClear_clicked()`
这个槽**不报编译错误、不报运行时错误**,只是从此再也不会被调用——`connectSlotsByName`
找不到匹配的 `objectName` 时只是静默跳过。这是「静默失败」坑点家族的第三个成员
(前两个是旧 `SIGNAL()/SLOT()` 字符串语法、重复 `connect`)。
- 结论:显式 `connect()` 虽然多写几行,但改名/删控件时编译器/IDE 能帮你追踪引用,
排查成本远低于依赖命名约定的隐式连接。项目里**推荐显式 connect**`on_xxx_yyy()`
自动连接更适合 Qt Designer 快速原型阶段。
## 验证方式(自测模式)
```bash
QT_QPA_PLATFORM=offscreen tools/run_qt.sh qt_calculator_designer
# 自测用例与 ../calculator/ 完全一致:「7+3=10」「6÷0=Error」「4.5+0.5=5」
# 「12 退格→1」「2+3+4=9(链式运算)」,全部通过退出码 0
tools/run_qt.sh qt_calculator_designer # 有 X 环境:完整交互
```
## 课堂讲解建议
1. 先展示 `.ui` 文件本身是纯 XML`<widget class="QPushButton" name="btn7">…`)——
Qt Designer 只是这份 XML 的图形化编辑器,不是什么黑魔法;
2. 对照 `../calculator/qt_calculator.cpp``buildKeypad()`,逐行说明
`uic` 把这份 XML 翻译成了等价的 C++ 建控件代码(`build/` 里能翻出真实生成的
`ui_calculator_designer.h` 验证);
3. 演示自动连接的坑:把 `.ui` 里某个按钮的 `name` 改掉,重新构建,点击按钮
没反应——现场复现「改名静默失效」;
4. 讨论:两种方式怎么选?—— 快速原型/美术同学调界面用 Designer 更直观;
逻辑复杂、控件数量随数据动态变化(比如 Day5 的表格行)就必须手写代码搭建,
`.ui` 表单描述不了「运行时循环创建 N 个控件」。
## 参考
- 代码布局对照版:[`../calculator/`](../calculator/README.md)
- Qt 官方 Widgets 表单机制:`uic`User Interface Compiler+ `QMetaObject::connectSlotsByName`