05a685c952
- 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>
60 lines
3.6 KiB
Markdown
60 lines
3.6 KiB
Markdown
# 简易计算器 —— 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`
|