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>
77 lines
4.1 KiB
Markdown
77 lines
4.1 KiB
Markdown
# Day3 上午参考实现:计算器 → QMainWindow
|
||
|
||
> 对应教案 [`OUTLINE_4DAY.md`](../../OUTLINE_4DAY.md) Day3 上午「QMainWindow / 对话框
|
||
> QDialog」+ [`ASSIGNMENTS.md`](../../ASSIGNMENTS.md) Day3 上午课堂练习。手工维护,
|
||
> 非生成产物。
|
||
|
||
## 定位:把 Day2 增强版计算器装进 QMainWindow
|
||
|
||
以 Day2 增强版计算器 [`../calculator_designer_ext/`](../calculator_designer_ext/README.md)
|
||
的 `CalculatorDesigner`(`QWidget`,含表达式求值 + 括号)为**中心部件**,给它套上
|
||
`QMainWindow` 外壳:菜单栏 / 状态栏 / 历史停靠窗。**计算器面板本身的输入与求值逻辑
|
||
一字未改**——这正是「界面外壳升级、核心部件不动」的关注点分离。
|
||
|
||
## 与 Day2 增强版的差异(仅两处,集中在 `calculatordesigner.{h,cpp}`)
|
||
|
||
| 改动 | 位置 | 目的 |
|
||
|---|---|---|
|
||
| 新增 `evaluated(expr, result)` 信号 | `calculatordesigner.h/.cpp` | 按 `=` 求值成功后发出,供历史停靠窗订阅(演示「给已有部件加信号,与外壳通信」) |
|
||
| 新增 `loadExpression(expr)` 方法 | `calculatordesigner.h/.cpp` | 把一条历史表达式回填到编辑区,配合历史双击 |
|
||
|
||
`expressionevaluator.{h,cpp}` / `widget.ui` 与 Day2 增强版完全一致(自包含复制,便于
|
||
学员单读 Day3 代码不跳目录)。
|
||
|
||
## 与 [`../mainwindow_showcase/`](../mainwindow_showcase/README.md) 的分工对照
|
||
|
||
两者同为 Day3 上午教学载体,风格刻意对立,覆盖不同教学诉求:
|
||
|
||
| | `mainwindow_showcase` | 本例 `calculator_mainwindow` |
|
||
|---|---|---|
|
||
| 形态 | 极简文本编辑器(`QTextEdit` 中心) | 计算器(`CalculatorDesigner` 中心) |
|
||
| 主窗体结构来源 | `.ui` 表单(Designer) | 纯代码 |
|
||
| 信号槽 | `on_<obj>_<sig>` 自动连接 | 显式 `connect()` |
|
||
| 教学侧重 | QMainWindow 六大组件齐全(含资源 `.qrc`) | 作业线应用 + 显式 connect 坑卡 |
|
||
| 用法 | 教师讲「组件协议」时演示 | 学员课堂练习对照、作业验收参考 |
|
||
|
||
**坑卡对照**:`mainwindow_showcase` 用自动连接,控件改名静默失效;本例用显式 `connect`,
|
||
`QAction` 忘 connect 时菜单点了没反应——两种「静默失败」在同一节课形成对照。
|
||
|
||
## 教学要点(对应 OUTLINE_4DAY.md Day3 上午)
|
||
|
||
1. **中心部件必须 `setCentralWidget`**:`mainwindow.cpp` 构造函数里 `setCentralWidget(m_calc)`。
|
||
直接往 `QMainWindow` 上 `addWidget` 是 Day3 上午坑卡——布局行为不可预期。
|
||
2. **菜单 + QAction + 显式 connect**:`buildMenu()` 逐菜单逐 `QAction` 建,每个都 `connect`。
|
||
`m_actAbout` 若忘 `connect`,菜单显示正常、点了没反应。
|
||
3. **模态对话框**:`onAbout()` 用 `QMessageBox::about`,内部 `exec()` 阻塞等关闭。
|
||
4. **非模态停靠窗**:`QDockWidget` + `addDockWidget(Qt::RightDockWidgetArea, ...)`,
|
||
可拖动 / 浮动 / 关闭(`QDockWidget` 默认行为)。与 `p03/ch06` 三个 modeless 对照文件
|
||
呼应「非模态对象必须活过函数作用域」——停靠窗是 `new` 在堆上 + parent=`this`。
|
||
5. **信号槽跨对象通信**:`CalculatorDesigner::evaluated` → `MainWindow::onEvaluated`,
|
||
外壳订阅核心部件的信号,二者解耦。
|
||
|
||
## 构建与运行
|
||
|
||
```bash
|
||
# 构建(仓库根;Qt 5.14.2)
|
||
cmake --build build --target qt_calculator_mainwindow
|
||
|
||
# 离屏自测(9 组计算用例 + 历史追加/双击回填/清空,退出码 0 即全过)
|
||
PATH=E:/Qt/Qt5.14.2/5.14.2/mingw73_64/bin:$PATH \
|
||
QT_QPA_PLATFORM=offscreen \
|
||
./build/docs/teaching/examples/qt_calculator_mainwindow.exe; echo "exit=$?"
|
||
|
||
# 有 GUI 环境直接看窗口
|
||
./build/docs/teaching/examples/qt_calculator_mainwindow.exe
|
||
```
|
||
|
||
## 自测用例
|
||
|
||
`MainWindow::runSelfTest()`(offscreen 自动执行)覆盖:
|
||
|
||
- Day2 全部 9 组计算用例(验证升级外壳后计算行为不变)
|
||
- 按等号后历史停靠窗追加 `"expr = result"` 条目
|
||
- 除零 `Error` **不**进历史(`evaluated` 只在求值成功时 emit)
|
||
- 历史双击 → 表达式回填到编辑区
|
||
- 「清空历史」后列表为空
|
||
- 「关于」action 已创建并显式连接(GUI 弹窗验证靠现场演示)
|