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

4.1 KiB
Raw Permalink Blame History

Day3 上午参考实现:计算器 → QMainWindow

对应教案 OUTLINE_4DAY.md Day3 上午「QMainWindow / 对话框 QDialog」+ ASSIGNMENTS.md Day3 上午课堂练习。手工维护, 非生成产物。

定位:把 Day2 增强版计算器装进 QMainWindow

以 Day2 增强版计算器 ../calculator_designer_ext/CalculatorDesignerQWidget,含表达式求值 + 括号)为中心部件,给它套上 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/ 的分工对照

两者同为 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. 中心部件必须 setCentralWidgetmainwindow.cpp 构造函数里 setCentralWidget(m_calc)。 直接往 QMainWindowaddWidget 是 Day3 上午坑卡——布局行为不可预期。
  2. 菜单 + QAction + 显式 connectbuildMenu() 逐菜单逐 QAction 建,每个都 connectm_actAbout 若忘 connect,菜单显示正常、点了没反应。
  3. 模态对话框onAbout()QMessageBox::about,内部 exec() 阻塞等关闭。
  4. 非模态停靠窗QDockWidget + addDockWidget(Qt::RightDockWidgetArea, ...) 可拖动 / 浮动 / 关闭(QDockWidget 默认行为)。与 p03/ch06 三个 modeless 对照文件 呼应「非模态对象必须活过函数作用域」——停靠窗是 new 在堆上 + parent=this
  5. 信号槽跨对象通信CalculatorDesigner::evaluatedMainWindow::onEvaluated 外壳订阅核心部件的信号,二者解耦。

构建与运行

# 构建(仓库根;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 弹窗验证靠现场演示)