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>
431 lines
33 KiB
Markdown
431 lines
33 KiB
Markdown
# 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 天讲授(Day1–4)+ 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:00–12:00 课堂练习+工程师答疑**(1h);下午 **13:30–16:00 讲授**、
|
||
**16:00–17:00 课堂作业+答疑**(1h)。
|
||
|
||
### 0.2 显式假设
|
||
|
||
1. **受众**:学员已掌握 C++ 基础语法与 OOP 概念,Day1 定位是「回顾和提升」。
|
||
仍用 [`PRETEST.md`](PRETEST.md)(10 题/10 分钟,双平行卷)实测:**Day1 上午
|
||
「OOP 基础回顾」开讲前**发卷,按结果决定回顾环节的推进速度(分层预案见 PRETEST)。
|
||
2. **讲授块内部节奏**:2.5h 纯讲对中初级学员超出注意力极限,本设计把每个讲授块
|
||
切成 **3–4 个「讲 25–30min + 随堂微练 10–15min」循环**(新安排的产出列本就
|
||
含「课堂练习」);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/Ninja(Part1)、隔离 Qt 5.14.2(Part3),
|
||
构建命令见根 [`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)) | 无仓库代码,讲座式 |
|
||
| 环境搭建 + CMake(30min 讲 + 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:00–12: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:00–17: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:00–12: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
|
||
|
||
| 环节 | 内容 | 素材 |
|
||
|---|---|---|
|
||
| QMainWindow(45min 讲 + 20min 练) | 主窗口架构:菜单栏/工具栏/状态栏/中心部件/停靠窗 | `p03/ch05/central_widget.cpp`、`dock_widget.cpp`;综合演示 [`examples/mainwindow_showcase/`](examples/mainwindow_showcase/README.md)(极简文本编辑器,.ui 表单 + 自动连接,覆盖 wiki ch05 六大组件) |
|
||
| QDialog(45min 讲 + 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:00–12: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 框架层(Day2–4 + 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. 评估 C:Day6–10 项目开发就绪度
|
||
|
||
| 项目必备能力 | 训练强度 | 位置 |
|
||
|---|---|---|
|
||
| 主窗口+菜单+对话框的标准桌面骨架 | 讲+练+案例 | Day3 + Day5 |
|
||
| 控件/布局/美化 | 讲+练+作业(计算器线) | Day2–3 |
|
||
| 对象间通信(信号槽三种写法) | 讲+练 | Day2 |
|
||
| 数据持久化(JSON round-trip) | 讲+练+作业+案例 | Day4–5 |
|
||
| 表格类数据展示 | 演示+案例 | 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` 已补两版关系说明。
|