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

431 lines
33 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.
# 4 天课堂设计(对齐 2026-07 新版 10 天安排)+ 中初级学员适配性评估
> **依据**2026-07-05 收到的新版 10 天安排(正式全文见
> [`docs/SCHEDULE_2026_10DAY.md`](../SCHEDULE_2026_10DAY.md),简表见 §0.1),取代
> `docs/TRAINING_PLAN_2026.md` 的旧执行计划作为课堂设计基准。新安排本身就是
> 「**4 天讲授(Day14+ Day5 综合案例讲解 + Day6–10 项目开发/答辩**」结构,
> 因此本文即新基准下的正式教案大纲;此前对齐旧方案书的 5 天版
> [`OUTLINE.md`](OUTLINE.md) 保留作历史参照与素材库(其 24 张概念/坑卡在本文
> 全部复用)。幻灯片 `day1.html`…`day5.html` **已按本文重排**(§9 落地状态)。
> Day2–4 课堂练习/课后作业的分层(基础版+挑战版)作业单见
> [`ASSIGNMENTS.md`](ASSIGNMENTS.md)。
## 0. 基准与显式假设(供随时纠偏)
### 0.1 新版 10 天安排(简表,讲授部分逐条对应)
| 天 | 时段 | 内容 |
|---|---|---|
| 1 | 上午讲 | 开训典礼;C++ 常用技术和框架(讲座);开发环境搭建;Makefile/CMake;面向对象基础回顾(类/对象/封装) |
| 1 | 下午讲 | C++ 核心特性(继承与多态、虚函数);内存管理(指针、引用与动态分配);STL 常用容器简介 |
| 2 | 上午讲 | Qt 概述;创建 Qt 项目;第一个 Qt 小程序 |
| 2 | 下午讲 | 信号槽机制;项目案例:简易计算器 |
| 3 | 上午讲 | QMainWindow;对话框 QDialog |
| 3 | 下午讲 | 布局管理器;常用控件 |
| 4 | 上午讲 | Qt 消息机制和事件;绘图事件及表格事件 |
| 4 | 下午讲 | 文件系统 |
| 5 | 全天 | 综合项目案例讲解(本文 §8 给出案例设计) |
| 6–10 | — | 学员项目开发;Day10 下午项目答辩 |
每个半天的固定时段结构:**08:30–11:00 讲授**2.5h,产出=课堂代码+笔记+随堂练习)、
**11:0012:00 课堂练习+工程师答疑**1h);下午 **13:3016:00 讲授**
**16:0017:00 课堂作业+答疑**1h)。
### 0.2 显式假设
1. **受众**:学员已掌握 C++ 基础语法与 OOP 概念,Day1 定位是「回顾和提升」。
仍用 [`PRETEST.md`](PRETEST.md)(10 题/10 分钟,双平行卷)实测:**Day1 上午
「OOP 基础回顾」开讲前**发卷,按结果决定回顾环节的推进速度(分层预案见 PRETEST)。
2. **讲授块内部节奏**:2.5h 纯讲对中初级学员超出注意力极限,本设计把每个讲授块
切成 **34 个「讲 2530min + 随堂微练 1015min」循环**(新安排的产出列本就
含「课堂练习」);11:00/16:00 后的整段练习时间做当天的任务卡。
3. **新安排未点名的旧主题的处置**(关键决策,§4 有完整对照):QSS 并入 Day3 下午
(新安排该时段目标明含「美化」);JSON 并入 Day4 下午(「用户数据的保存与读取」
的自然载体);表格用 QTableWidget 讲、Model/View 降为延伸钩子;**QThread 移入
Day5 综合案例的「提升」环节**(理由与风险见 §6);动画/状态机降为自学指针;
Vcpkg 降为 CMake 环节的 1 分钟概念;OpenCV 移除(旧方案书本就标注可选)。
4. 工具链沿用仓库现状:host gcc/g++ + CMake/NinjaPart1)、隔离 Qt 5.14.2Part3),
构建命令见根 [`README.md`](../../README.md)Makefile 只在 Day1 讲「CMake 生成
构建系统」时作对照概念,不单独实操。
---
## 1. 四天总览(主题 → 仓库资产映射)
| Day | 上午 | 下午 | 当日作业产出 |
|---|---|---|---|
| 1 | 开训 + C++ 技术版图 + 环境/CMake `CMakeLists.txt` + OOP 回顾 `p01/ch04` | 继承/多态/虚析构 `p01/ch04/s08` + 内存管理 `p01/ch03` + STL `p01/ch09` | Part1 全绿构建 + 2 道 C++ 改错题 |
| 2 | Qt 概述 + 项目创建 + 第一个程序 `p03/ch02` `ch03` | 信号槽 `p03/ch04` → 计算器案例 | 可运算的简易计算器 |
| 3 | QMainWindow `p03/ch05` + QDialog `p03/ch06` | 布局/控件 `p03/ch08` + QSS `examples/qss_styling` | 计算器升级:主窗口化 + 美化 |
| 4 | 事件机制 `p03/ch09` + 绘图 `p03/ch10` + 表格 | 文件 IO `p03/ch11` + JSON `examples/json_io` | 本地数据存储小工具(写入→重启→读回) |
四天作业刻意串成一条线:Day2 计算器 → Day3 给它套 QMainWindow+QSS → Day4 数据
落盘,Day5 综合案例是同一能力栈的完整版,学员进入 Day6 项目开发前已完整走过
3 轮「编码→构建→运行→演示」闭环。
---
## 2. 逐天设计
概念/坑卡标注:**[沿用]**= 取自 5 天版 `OUTLINE.md` 的同名卡片(内容不重抄,
以该文件为准);**★[新增]**= 本轮中初级误区审计(§5)补入的卡片,正文写全。
### Day 1 上午:开训 / C++ 技术版图 / 环境与 CMake / OOP 回顾
讲授块切分(2.5h):
| 环节 | 内容 | 素材 |
|---|---|---|
| 开训典礼(≈40min,非教学) | 团队/实训安排/考评要求 | 组织方主持 |
| C++ 常用技术和框架(讲座 25min) | 桌面(Qt)/后端/嵌入式/游戏四大版图;C++11→20 标准演进一页图(兴趣钩子→ [`MODERN_CPP.md`](MODERN_CPP.md) | 无仓库代码,讲座式 |
| 环境搭建 + CMake30min 讲 + 15min 随堂练) | 用本仓库当真教材:`-S -B` 生成 / `--build` 编译两阶段;`option()``add_executable`Makefile 是 CMake 的生成目标之一(对照概念);Vcpkg 一分钟概念 | 根 `CMakeLists.txt``p01/CMakeLists.txt` |
| **PRETEST 摸底(10min** | 发 A/B 卷,收卷即批 L1 题 | [`PRETEST.md`](PRETEST.md) |
| OOP 基础回顾(30min,按摸底结果调速) | 类/对象/封装;namespace 作用域 | `p01/ch04``p01/ch03/namespace_syntax.cpp` |
概念/坑卡:**CMake 项目构建[沿用]**、**namespace 作用域[沿用]**、外加——
- ★**编译错误 vs 链接错误的排查分界**:概念——`error:` 带文件行号是编译期(语法/
类型),`undefined reference` 无行号是链接期(缺定义/缺库/缺目标文件),排查方向
完全不同;坑——中初级学员见到 `undefined reference` 习惯回头查语法,方向就错了。
此卡是 Day2「忘写 `Q_OBJECT` 报链接错」的前置铺垫。
11:0012:00 课堂练习:**任务卡 1**——独立完成 Part1 配置+构建
`cmake -S . -B build -G Ninja -DBUILD_QT_PART=OFF && cmake --build build`
144 目标全绿,能说出 `option(BUILD_QT_PART)` 的作用)。
### Day 1 下午:继承与多态 / 内存管理 / STL 简介
| 环节 | 内容 | 素材 |
|---|---|---|
| 继承/多态/虚函数(40min 讲 + 15min 练) | 虚函数表机制、重写 vs 重载;虚析构与内存泄漏 | `p01/ch04/s08/virtual_dtor_purpose.cpp`;函数重载 `p01/ch03/function_overload_mechanism.cpp` |
| 内存管理(40min 讲 + 15min 练) | 指针/引用/动态分配;引用的本质;**所有权**——谁负责 delete | `p01/ch03/reference_essence.cpp` |
| STL 常用容器(25min 讲 + 15min 练) | vector/map/string 三件套;迭代器统一接口 | `p01/ch05/class_template_basics.cpp``p01/ch09/s03/vector_iterator.cpp` |
概念/坑卡:**函数重载决议[沿用]**、**引用的本质[沿用]**、**虚析构与内存
泄漏[沿用]**、**模板与 STL 速览[沿用]**(含迭代器失效坑)、外加——
- ★**所有权心智模型:谁负责 delete**:概念——内存管理的核心问题不是「会不会 new」
而是「这块资源归谁管、由谁释放」,现代答案是 RAII/智能指针(`unique_ptr` 独占、
`shared_ptr` 共享,详见 [`MODERN_CPP.md`](MODERN_CPP.md) §2);坑——双重释放、
忘记释放、释放后使用三兄弟全部源于所有权不明。**本卡是 Day2 Qt 对象树的前置
铺垫**:Qt 用父子所有权回答同一个问题,两套体系混用有专门的坑(Day2)。
16:0017:00 作业:从 `docs/ERRATA.md` 挑 2 条与今天知识点相关的记录(虚析构/引用
/重载类),在源文件里理解「wiki 原文错在哪、为什么」,各写一句话解释;选做——用
`tools/std_probe.py` 验证一个版本差异点(对照 `docs/VERSION_NOTES.md`)。
### Day 2 上午:Qt 概述 / 创建 Qt 项目 / 第一个 Qt 小程序
| 环节 | 内容 | 素材 |
|---|---|---|
| Qt 概述(25min | Qt 是什么/能做什么;Qt 5.14 vs 系统 Qt 隔离(本仓库 `.qt514/` 的做法);模块结构 Core/Gui/Widgets | 根 `CMakeLists.txt` 的 Qt 版本断言 |
| 创建 Qt 项目(30min 讲 + 15min 练) | CMake 方式创建(`find_package(Qt5)`、AUTOMOC);构建开关 `-DBUILD_QT_PART=ON` | `p03/CMakeLists.txt``p03/ch02/CMakeLists.txt` |
| 第一个 Qt 小程序(40min 讲 + 20min 练) | `QApplication` + `exec()` 事件循环;控件创建与显示;QObject 对象树 | `p03/ch02/minimal_qt_app.cpp``p03/ch03/button_creation.cpp` |
概念/坑卡:**最小 Qt 程序结构[沿用]**(含忘 `Q_OBJECT` 链接错——正好接 Day1
链接错误卡)、**控件创建与显示[沿用]**(对象树/parent)、外加——
- ★**栈对象与父子所有权打架**:概念——Qt 父子树在 parent 析构时 `delete` 所有子
对象,这要求子对象必须建在堆上;坑——把带 parent 的控件建在栈上
`QPushButton btn(&window);`),作用域结束栈析构一次、parent 再 delete 一次 →
双重释放崩溃。与 Day1 所有权卡呼应:**Qt 树管的对象不要再用智能指针/栈/手动
delete 去管**,一个对象只能有一个所有者。
11:0012:00 课堂练习:跑通 `minimal_qt_app``button_creation`
`QT_QPA_PLATFORM=offscreen tools/run_qt.sh <target>` 退出码 0);改造:窗口
标题、按钮文字换成自己的学号姓名(第一次触碰 QString 中文——为下午的编码卡埋点)。
### Day 2 下午:信号槽机制 → 案例:简易计算器
| 环节 | 内容 | 素材 |
|---|---|---|
| 信号槽(50min 讲 + 20min 练) | 观察者模式;内置/自定义/lambda 三种写法;新旧语法对比;连接方式 Direct/Queued/Auto | `p03/ch04/builtin_signal_slot.cpp``custom_signal_slot.cpp``lambda_signal_slot.cpp` |
| 计算器案例(40min 带练) | 数字/运算键盘 + 点击信号槽 + 结果显示;**布局用教师提供的 `QGridLayout` 脚手架「先用后学」**(布局原理 Day3 下午讲透,今天只求能排出键盘) | `p03/ch03` + `p03/ch04` + 教师参考实现 [`examples/calculator/`](examples/calculator/README.md)(另有 [`examples/calculator_designer/`](examples/calculator_designer/README.md) Qt Designer `.ui` 对照版,含「自动连接静默失效」坑点) |
概念/坑卡:**信号槽三种写法[沿用]**(含旧语法静默失败、`QOverload` 消歧义)、外加——
- ★**lambda 槽的生命周期与第五参数**:概念——`connect` 第五参数(context object
决定连接的生存期,lambda 槽应传 context,对象销毁连接自动断开;坑——lambda 按引用
捕获局部变量、或捕获 `this` 而不传 context,对象销毁后信号再来就是悬空访问——这是
从「能用 lambda」到「敢在项目里用 lambda」之间最大的坑。
- ★**重复 connect 导致槽触发多次**:概念——`connect` 每调一次新增一条连接,同一对
信号槽连两次槽就被调两次(`Qt::UniqueConnection` 可防重);坑——把 `connect` 写在
会被多次执行的函数里,现象是「点一次按钮弹两次框」,学员往往去查按钮而不是查连接。
- ★**QString 与中文编码**:概念——`QString` 内部是 UTF-16,与 `std::string`(字节串)
互转要经 `toUtf8()`/`fromUtf8()`;坑——源码不存成 UTF-8、或用 `QString(char*)`
隐式转换中文字面量,界面就是乱码。**中文教学环境第一天写界面必踩**,上午练习的
学号姓名改造就是现场复现点。
16:00–17:00 作业:完成计算器——至少支持两个数 + 加减乘除,结果正确显示在
`QLabel`/`QLineEdit`;界面不重叠、按钮可点击(验收同 5 天版计算器任务卡 1)。
### Day 3 上午:QMainWindow / 对话框 QDialog
| 环节 | 内容 | 素材 |
|---|---|---|
| QMainWindow45min 讲 + 20min 练) | 主窗口架构:菜单栏/工具栏/状态栏/中心部件/停靠窗 | `p03/ch05/central_widget.cpp``dock_widget.cpp`;综合演示 [`examples/mainwindow_showcase/`](examples/mainwindow_showcase/README.md)(极简文本编辑器,.ui 表单 + 自动连接,覆盖 wiki ch05 六大组件) |
| QDialog45min 讲 + 20min 练) | 模态 vs 非模态(三种非模态写法对比:栈/堆/`WA_DeleteOnClose`);标准对话框 `QMessageBox`/`QFileDialog` | `p03/ch06/modal_dialog.cpp``modeless_dialog_stack.cpp``modeless_dialog_heap.cpp``modeless_dialog_deleteonclose.cpp``message_box_question.cpp``file_dialog.cpp` |
概念/坑卡(本节两张为本文新写,5 天版未覆盖 ch05/ch06):
- **QMainWindow 结构**:概念——QMainWindow 不是「大号 QWidget」,它有固定的区域
布局协议(菜单/工具/状态/中心/停靠各就其位),中心部件必须 `setCentralWidget`
显式安放;坑——直接往 QMainWindow 上 `addWidget`/摆控件而不设中心部件,布局行为
不可预期;菜单动作 `QAction` 忘了 `connect` 到槽,菜单显示正常点了没反应。
- **模态与非模态的生命周期**:概念——模态 `exec()` 阻塞等结果、返回值即用户选择;
非模态 `show()` 立即返回,对话框对象必须活过函数作用域(堆 + parent,或
`WA_DeleteOnClose` 自清理);坑——**栈上建非模态对话框 `show()` 完函数一返回就
析构,窗口一闪而过**——`p03/ch06` 三个 modeless 版本正是这个坑的对照教材,也是
Day2 栈/堆所有权卡的第三次复现。
11:0012:00 课堂练习:以 Day2 增强版计算器([`examples/calculator_designer_ext/`](examples/calculator_designer_ext/README.md))为起点,套上 QMainWindow——加菜单「帮助→关于」弹
`QMessageBox`;加一个「历史」停靠窗(可先放空 QLabel)。参考实现:
[`examples/calculator_mainwindow/`](examples/calculator_mainwindow/README.md)(纯代码
建菜单 + 显式 connect,与 `mainwindow_showcase``.ui` 自动连接形成坑卡对照)。
> 衔接说明:Day2 增强版 `CalculatorDesigner` 已是独立 `QWidget`Day3 上午只做
> 「外壳升级」——`setCentralWidget` 把它装进 `QMainWindow`,核心求值逻辑不动。
> 唯一新增是 `CalculatorDesigner` 加一个 `evaluated` 信号供历史停靠窗订阅(Day2
> 信号槽知识的复用)。详见参考实现 README。
### Day 3 下午:布局管理器 / 常用控件(+QSS 美化)
| 环节 | 内容 | 素材 |
|---|---|---|
| 布局管理器(40min 讲 + 15min 练) | QHBox/QVBox/QGrid;嵌套布局;伸缩因子——回收 Day2 计算器脚手架,讲透当时「先用后学」的部分 | `p03/ch08/custom_widget.cpp` |
| 常用控件(35min 讲 + 15min 练) | QLabel 文本/HTML/图片、QLineEdit、按钮族;资源系统 `.qrc` | `p03/ch08/label_text_html.cpp``label_pixmap.cpp``label_movie.cpp` |
| QSS 界面美化(25min 讲 + 20min 练) | 选择器/伪状态/层叠——对应新安排「自适应排版及**美化**」目标 | `docs/teaching/examples/qss_styling/qt_qss_styling.cpp` + [README](examples/qss_styling/README.md);作业线参考 [`examples/calculator_mainwindow_qss/`](examples/calculator_mainwindow_qss/README.md)(上午版 + 双主题 QSS |
概念/坑卡:**布局管理[沿用]**(同控件不能属两个布局;布局后 `setGeometry`
覆盖)、**资源系统 .qrc[沿用]**(路径静默失败/AUTORCC)、**QSS 美化[沿用]**
ID 选择器要 `setObjectName``setStyleSheet` 级联失控)。
16:00–17:00 作业:计算器升级——数字键/运算键/等号键用 QSS 区分颜色,至少 1 个按钮
`:hover``:pressed` 效果;整体布局改为可随窗口缩放(验收同 5 天版 QSS 任务卡)。
参考实现:[`examples/calculator_mainwindow_qss/`](examples/calculator_mainwindow_qss/README.md)(在
Day3 上午版基础上只加 QSS,演示「美化与逻辑正交」)。
### Day 4 上午:Qt 消息机制和事件 / 绘图事件及表格事件
| 环节 | 内容 | 素材 |
|---|---|---|
| 事件循环与派发(35min 讲 + 15min 练) | `exec()` 事件循环回收 Day2 概念;事件 vs 信号槽两套机制;**主线程阻塞=界面冻结**(为 Day5 QThread 提升埋点) | `p03/ch02/minimal_qt_app.cpp` |
| 事件拦截(30min 讲 + 15min 练) | 重写 `xxxEvent()` vs `installEventFilter()``accept()`/`ignore()` 传播 | `p03/ch09/event_override_customwidget.cpp``event_filter_mainwindow.cpp``mouse_event.cpp` |
| 绘图事件(30min 讲 + 15min 练) | `paintEvent` + `QPainter``update()` 异步重绘;绘图设备一瞥 | `p03/ch10/qpainter_basic.cpp`(设备类 `paint_device_*.cpp` 作参考) |
| 表格(15min 演示) | `QTableWidget` 单元格填充与 `cellClicked`/`itemChanged` 事件(item 类控件够项目用);Model/View 架构一页概念 + 延伸钩子 | `docs/teaching/examples/table_widget/qt_table_widget_basics.cpp`M/V 钩子:`examples/model_view/` |
概念/坑卡:**事件循环:事件 vs 信号[沿用]**、**自定义事件处理/事件过滤器
[沿用]**(重写忘调基类丢默认行为)、**QPainter 绘图[沿用]**`paintEvent`
之外绘制 UB;忘 `update()` 不重画)、**Model/View 架构[沿用,降为概念页]**。
11:00–12:00 课堂练习:给控件装事件过滤器拦截鼠标按下并打印坐标;在 `paintEvent`
里画一个组合图形(棋盘格或仪表盘刻度)。
### Day 4 下午:文件系统(+JSON
| 环节 | 内容 | 素材 |
|---|---|---|
| 文件读写(40min 讲 + 20min 练) | `QFile`/`QTextStream`/`QDataStream``QIODevice` 统一抽象 | `p03/ch11/qfile_basic.cpp``qtextstream_io.cpp``qdatastream_io.cpp` |
| JSON 解析与写入(35min 讲 + 20min 练) | round-trip 正确性标准;`QJsonDocument/Object/Array/Value` | `docs/teaching/examples/json_io/qt_json_parse_write.cpp` + [README](examples/json_io/README.md) |
概念/坑卡:**QIODevice 统一读写抽象[沿用]**(`open()` 不检查静默失败)、
**JSON 序列化/反序列化[沿用]**`QJsonParseError` 不检查静默空文档;类型不匹配
返回默认值不报错)、外加——
- ★**相对路径与工作目录**:概念——`QFile("data.json")` 的相对路径基于**进程当前
工作目录**,不是源码目录也不一定是可执行文件目录;IDE、终端、`tools/run_qt.sh`
三种跑法工作目录可能各不相同;坑——「IDE 里能读到文件,命令行跑就说不存在」,
中初级学员几乎必问。正解:`QCoreApplication::applicationDirPath()` 拼路径,或
只读资源走 `.qrc`(呼应 Day3 资源卡)。
- ★**文本编码再遇(文件版)**:概念——`QTextStream` 默认编码随平台/区域设置而变
(Qt 5 默认本地编码),跨平台交换文本必须显式 `setCodec("UTF-8")`;坑——Windows
写的文件 Linux 读出乱码(或反过来)。与 Day2 的 QString 编码卡同根源、隔两天
第二次出现,刻意间隔重复形成「编码要显式指定」的条件反射。
16:00–17:00 作业:本地数据存储小工具——「学员信息」结构(姓名/成绩/标签)增加记录
并保存到 JSON 文件,重启程序读回全部记录(至少 2 条、字段不丢,验收同 5 天版
存储任务卡 2)。**这是 Day5 综合案例的直接前身。**
---
## 3. Day5 综合项目案例讲解(全天,衔接设计)
新安排 Day5 的目标是「通过综合案例讲解 Qt 开发流程、规范及方法」。建议案例:
**「学员信息管理器」**——把四天作业线收束成完整小软件,正好覆盖全部已学内容并
补上项目开发前的最后三块拼图:
| 时段 | 内容 | 覆盖 |
|---|---|---|
| 上午 1 | 需求拆解 → 界面骨架:QMainWindow + 菜单/工具栏 + QTableWidget 列表 + 增改对话框 | Day3 全部 + Day4 表格 |
| 上午 2 | 数据层:记录结构 ↔ QJson 序列化 ↔ 落盘读回;信号槽把界面和数据接起来 | Day4 下午 + Day2 |
| 下午 1 | **提升:QThread 防卡界面**——导入大文件时界面不冻结(worker 对象模式、跨线程不碰 GUI) | `docs/teaching/examples/qthread_worker/` + [README](examples/qthread_worker/README.md)(旧 5 天版 D4A 的概念/坑卡照用) |
| 下午 2 | 开发流程与规范:Git 提交粒度(对应任务粒度、信息可追溯,忌"update");代码走查怎么做;考评三维度(管理/技术/素养);分组定项目方向 | `docs/TRAINING_PLAN_2026.md` 质量保证节 + `docs/images/` 三图 |
| 兴趣钩子(穿插) | 动画/状态机各 5min 演示(给界面加转场动效的方向) | `examples/property_animation/``state_machine/` |
QThread 放 Day5 而非砍掉的理由:**「主线程阻塞=界面冻结」是学员项目里最高频的
崩溃/卡死来源**,新安排 Day1–4 没有它的位置,但综合案例的「导入数据」情节是它
最自然的出场时机;且 Day4 上午事件循环卡已埋点,Day5 只需 60–70 分钟就能讲透
worker 模式三件套(亲和性/moveToThread 时序/跨线程信号槽自动 Queued)。
---
## 4. 评估 A:新安排条目覆盖核对 + 旧主题去向
**新安排讲授条目 → 本设计位置**:逐条对齐(§2 各表第一列即新安排原文条目),
无遗漏;「Makefile/CMake」按 §0.2 假设 4 以 CMake 实操为主、Makefile 为对照概念。
**旧 5 天版有、新安排未点名的主题的去向**
| 旧主题 | 去向 | 理由 |
|---|---|---|
| QSS 美化 | Day3 下午(正式讲授) | 新安排 Day3 下午目标原文含「美化」;且计算器案例线需要它 |
| JSON | Day4 下午(正式讲授) | 「用户数据的保存与读取」的事实标准载体;项目实作必用 |
| Model/View | Day4 上午概念页 + 延伸钩子 | 项目层面 QTableWidget 够用;完整 M/V 对中初级学员超纲 |
| QThread 多线程 | Day5 提升环节(保留讲授) | 见 §3 论证;完全砍掉是项目期最大风险点 |
| 动画/状态机 | Day5 钩子 + 自学指针 | 项目使用频率低;示例与 README 完整保留 |
| Scrum/团队协同/考核标准 | 开训典礼(组织方)+ Day5 下午 2 | 讲授权重下调,但 Git 习惯与考评三维度保留在进项目前最后一课 |
| Vcpkg | Day1 CMake 环节 1 分钟概念 | 新安排未点名;保留「包管理器是什么」的认知即可 |
| OpenCV | 移除(不再作自学指针占课时) | 旧方案书即标注可选;新安排无此条 |
## 5. 评估 B:中初级学员常见误区/盲点覆盖审计(核心交付)
审计画像:「有一定 C++ 基础」= PRETEST L1 全对、L2 部分对的学员。逐条核对三个
层面的高频误区是否有对应「概念/坑」卡。**✔=沿用 5 天版已覆盖卡;★=本轮新增;
☆=本文为 ch05/ch06 新写;—=有意不覆盖(附理由)**。
**C++ 语言层(Day1 集中处理)**
| 误区/盲点 | 覆盖 | 位置 |
|---|---|---|
| 引用可空/可重绑、值传递 vs 引用传递、悬空引用 | ✔ | Day1 下午 + PRETEST L1 |
| 虚析构缺失泄漏、多态机制、重写 vs 重载 | ✔ | Day1 下午 + PRETEST L2/L3 |
| 重载决议二义性、隐式转换扩大候选集 | ✔ | Day1 下午 + PRETEST L2 |
| 迭代器失效 | ✔ | Day1 下午 STL 卡 |
| 头文件 `using namespace` 污染 | ✔ | Day1 上午 namespace 卡 |
| **「谁负责 delete」所有权模型缺失** | ★ | Day1 下午新卡(内存管理环节,位置比旧版更贴切) |
| **编译错误 vs 链接错误分不清** | ★ | Day1 上午新卡 |
| static 初始化顺序、const 细则、移动语义细节 | — | 项目实作用不到临界深度;[`MODERN_CPP.md`](MODERN_CPP.md) 作自学 |
**Qt 框架层(Day24 + Day5**
| 误区/盲点 | 覆盖 | 位置 |
|---|---|---|
| 忘 `Q_OBJECT` → 链接错且不提宏 | ✔ | Day2 上午(有 Day1 链接卡打底) |
| 忘 `exec()` 窗口一闪而过、多个 QApplication | ✔ | Day2 上午 |
| 忘传 parent 泄漏 | ✔ | Day2 上午 |
| **栈上建带 parent 的控件 → 双重释放** | ★ | Day2 上午新卡 |
| **非模态对话框建在栈上一闪而过** | ☆ | Day3 上午新卡(同一所有权误区第三次复现,ch06 三个 modeless 对照文件是现成教材) |
| **lambda 槽捕获悬空 / 缺 context 参数** | ★ | Day2 下午新卡 |
| **重复 connect → 槽触发多次** | ★ | Day2 下午新卡 |
| 旧字符串语法静默失败、重载信号消歧义 | ✔ | Day2 下午 |
| **QString/std::string 混淆、中文乱码** | ★ | Day2 下午新卡(上午练习已现场埋复现点) |
| QMainWindow 不设中心部件、QAction 忘连接 | ☆ | Day3 上午新卡 |
| 同控件属两个布局、布局后手动 `setGeometry` 被覆盖 | ✔ | Day3 下午 |
| `.qrc` 路径错静默失败 | ✔ | Day3 下午 |
| QSS 级联失控、ID 选择器要 objectName | ✔ | Day3 下午 |
| 重写事件函数忘调基类 | ✔ | Day4 上午 |
| `paintEvent` 之外绘制 UB、忘 `update()` | ✔ | Day4 上午 |
| 改模型不发信号视图不刷新 | ✔(概念页) | Day4 上午 |
| `open()` 不检查、JSON 解析错误静默 | ✔ | Day4 下午 |
| **相对路径随工作目录漂移** | ★ | Day4 下午新卡 |
| **QTextStream 默认编码平台相关 → 跨机乱码** | ★ | Day4 下午新卡 |
| 工作线程碰 GUI 崩溃、moveToThread 时序 | ✔ | Day5 提升环节(Day4 上午已埋「阻塞=冻结」认知) |
| Qt Designer/.ui 工作流 | — | 本课程纯代码路线(仓库示例均无 .ui);项目期按需补 |
**工程/协作层**
| 误区/盲点 | 覆盖 | 位置 |
|---|---|---|
| CMake「生成 vs 构建」两阶段混淆 | ✔ | Day1 上午 |
| 新标准特性 ≠ 工具链可用 | ✔ | Day1 讲座钩子 + `std_probe.py` 作业选做 |
| commit 粒度失控、信息写"update" | ✔ | Day5 下午 2(进项目前最后一课,即时生效) |
| 只重技术忽略考评其余维度 | ✔ | Day5 下午 2 |
**审计结论**:共 **10 张新卡**(★8 + ☆2),集中三条主线:①**所有权与生命周期**
(谁 delete → 栈控件双重释放 → 非模态对话框一闪而过 → lambda 捕获悬空,四天内
四次复现同一心智模型,这是「学过 C++ 语法」与「写得出不崩的 Qt 程序」之间最大的
鸿沟);②**编码与路径**(中文乱码 Day2 → 文件乱码 Day4 → 工作目录 Day4,中文教学
环境必踩且旧版完全空白);③**连接语义**(重复 connect、context 参数,现象诡异、
自查困难,教了能省项目期大量答疑)。新安排把 C++ 扩到整天,反而让 ①在 Day1 就能
立住地基——比旧 5 天版(C++ 只有半天)对中初级学员更友好。
## 6. 评估 CDay610 项目开发就绪度
| 项目必备能力 | 训练强度 | 位置 |
|---|---|---|
| 主窗口+菜单+对话框的标准桌面骨架 | 讲+练+案例 | Day3 + Day5 |
| 控件/布局/美化 | 讲+练+作业(计算器线) | Day2–3 |
| 对象间通信(信号槽三种写法) | 讲+练 | Day2 |
| 数据持久化(JSON round-trip | 讲+练+作业+案例 | Day45 |
| 表格类数据展示 | 演示+案例 | Day4–5 |
| 事件拦截/自绘 | 讲+练 | Day4 |
| 耗时操作不卡 UI | 讲+案例(Day5 提升) | Day4 埋点 + Day5 |
| 崩溃自查(所有权/编码/连接三主线) | 10 张坑卡 + 四次间隔复现 | Day1–4 贯穿 |
| Git/流程/考评认知 | 讲 | Day5 |
| 综合组装 | 全程案例走查 | Day5 |
**结论:就绪度充分**,且作业线(计算器→主窗口化→数据落盘→综合案例)保证每个学员
进项目前至少完成 3 个递进的可运行程序。两个前提条件:① PRETEST 摸底通过(不通过
则触发 PRETEST 分层预案,Day1 下午减少 STL 时长、加固 OOP);② **Day5 必须保住
QThread 提升环节**——若 Day5 案例讲解超时挤掉它,项目期「界面冻结/跨线程崩溃」
答疑成本会数倍返还,这是本设计标记的最高优先级保底项。
## 7. 评估 D:高阶兴趣钩子(每处 1–2 分钟点到 + 自学入口)
| Day | 钩子(挂在当天刚学的内容上) | 自学入口 |
|---|---|---|
| 1 | C++ 不是停滞的语言:11「几乎新语言」→ 20 四大件 → 26 反射;现场用 `std_probe.py` 编译验证一个新特性 | [`MODERN_CPP.md`](MODERN_CPP.md)、[`MODERN_CPP_20PLUS.md`](MODERN_CPP_20PLUS.md)(含本机 GCC 实测矩阵) |
| 2 | 信号槽的幕后:打开 `build/` 里真实的 `moc_*.cpp` 看 moc 生成了什么 | 本仓库构建产物 + Qt 元对象系统文档 |
| 3 | QSS 与前端 CSS 的同源关系;Qt Designer/QML 是另一条 UI 路线 | Qt 官方 Style Sheets 文档 |
| 4 | 今天的 QTableWidget 背后是完整的 Model/View 架构(数据/展示彻底解耦、一模型多视图) | `examples/model_view/` + Qt Model/View 长文 |
| 5 | QtConcurrent/线程池是 QThread 的更高抽象;动画/状态机给界面加转场 | `examples/property_animation/``state_machine/`、[`MODERN_CPP_20PLUS.md`](MODERN_CPP_20PLUS.md) §协程 |
设计原则:钩子全部是**当天内容的自然延伸**(学了信号槽→看 moc 产物;学了表格→
看 Model/View),不做空降的「高级话题清单」——好奇心要挂在已有的钩子上。
## 8. 风险与缓解
| 风险 | 缓解 |
|---|---|
| 2.5h 讲授块对中初级学员过长 | §0.2 假设 2 的「讲 25–30 + 练 10–15」循环切分;随堂微练全部有明确产出(跑通/改造/复现坑) |
| Day2 下午计算器早于布局课(新安排固有顺序) | 教师提供 QGridLayout 脚手架「先用后学」,Day3 下午回收讲透;脚手架片段随幻灯片提供 |
| Day5 案例讲解超时挤掉 QThread 提升 | 上午严格按 §3 时段推进;万一超时,砍动画/状态机钩子而非 QThread(§6 保底项) |
| PRETEST 摸底不达标 | Day1 下午 STL 环节让位 OOP 加固(PRETEST 分层预案);新安排 C++ 占整天,回旋余地本就比旧 5 天版大 |
| ~~表格环节无现成 QTableWidget 示例~~(已解决) | 已补 `examples/table_widget/qt_table_widget_basics.cpp`,离屏验证通过 |
## 9. 落地清单(2026-07-05 已全部执行)
1.**幻灯片重排**`day1.html``day5.html` 已按本文 §2/§3 重组(Day1 全 C++、Day3
新增 ch05/ch06、Day5 改综合案例结构);10 张新卡已按 `custom.css` 现有
`.concept-box`/`.pitfall-box` 样式补入(幻灯片内标注 ★/☆),「大纲↔幻灯片
一一对应」约定保持。
2. ✅ **坑点最小复现示例**已补入 `docs/teaching/examples/`(手工维护区,不影响生成器):
`pitfall_stack_widget``--crash` 触发真实双重释放崩溃)、`pitfall_lambda_capture`
`--dangle` 触发真实悬空访问)、`pitfall_double_connect`(确定性 2 次→1 次对比)、
`table_widget`QTableWidget 最小示例)。默认运行均为正确写法、离屏验证退出码 0。
3.**Day5 综合案例参考实现**`docs/teaching/examples/student_manager/`
QMainWindow + QTableWidget + 对话框 + JSON round-trip + QThread 后台导入;
离屏自测模式自动校验「写入→读回」与导入闭环)。
3.1 ✅ **Day2 案例参考实现**`docs/teaching/examples/calculator/`(代码
`QGridLayout` 版)+ `docs/teaching/examples/calculator_designer/`Qt Designer
`.ui` 对照版,含自动连接 `on_<objectName>_<signal>` 静默失效坑点);两版业务
逻辑一致,离屏自测覆盖加减乘除/链式运算/除零/退格 5 组用例。
3.2 ✅ **Day2 增强版计算器**`docs/teaching/examples/calculator_designer_ext/`
(在 Designer 版基础上把「立即计算」升级为「表达式求值」——独立 `ExpressionEvaluator`
递归下降解析器,支持运算符优先级 + 括号含嵌套/未闭合自动补全;双显示区;离屏自测
9 组用例含 `2+3*4=14``(2+3)*4=20`)。作为 Day3 的起点。
3.3 ✅ **Day3 上午 QMainWindow 组件综合演示**`docs/teaching/examples/mainwindow_showcase/`
(极简文本编辑器形态,`.ui` 表单 + `.qrc` 资源 + `on_<obj>_<sig>` 自动连接,覆盖
wiki ch05 的 5.1–5.6 六大组件;离屏退出码 0)。教师讲组件协议时用,与下方
`calculator_mainwindow` 形成 `.ui`/自动连接 vs 纯代码/显式 connect 的坑卡对照。
3.4 ✅ **Day3 上午参考实现**`docs/teaching/examples/calculator_mainwindow/`
(把 Day2 增强版 `CalculatorDesigner` 装进 `QMainWindow`:菜单/状态栏/历史停靠窗;
`CalculatorDesigner` 仅加 `evaluated` 信号 + `loadExpression` 方法供历史订阅/回填;
纯代码建菜单 + 显式 connect;离屏自测 9 组计算 + 历史追加/双击回填/清空)。
3.5 ✅ **Day3 下午参考实现**`docs/teaching/examples/calculator_mainwindow_qss/`
(上午版 + QSS 双主题美化:按键按功能分色 + `:hover`/`:pressed` + 深/浅主题切换;
与上午版仅 `mainwindow.{h,cpp}` 差异,演示「美化与逻辑正交」;离屏自测含主题切换
改变 `styleSheet` 的断言)。
4. ✅ 新 10 天安排正式文本已落入 [`docs/SCHEDULE_2026_10DAY.md`](../SCHEDULE_2026_10DAY.md)
`OUTLINE.md` §0 与幻灯片 `index.html` 已补两版关系说明。