Files
scuc-qt-course/docs/teaching/OUTLINE.md
T
张宗平 a6743fcea0 每个「讲」知识点补齐核心概念 + 常见的坑,幻灯片与大纲同步
此前一版「讲」部分基本只是代码演示(贴代码 + 一句出处说明),没有讲透
知识点本身的原理。改为覆盖清单原则:每个知识点在大纲里至少固定两项——
核心概念(是什么/为什么,不只是怎么写)+ 常见的坑(注意事项/误区),
课堂实际讲解深度按学员反馈现场调整,但大纲必须列全,以免漏讲或退化成
纯代码演示。

- custom.css 新增 .concept-box/.pitfall-box 卡片样式
- day1–5.html 每个知识点前插入对应卡片,内容与 OUTLINE.md 的覆盖清单一一对应
2026-07-02 16:25:46 +08:00

32 KiB
Raw Blame History

教案大纲 —「C++/Qt 方向」5 天实训(对齐官方方案书 Day1–5)

配套材料:docs/teaching/slides/day1.htmlday5.htmlreveal.js 交互幻灯片, 已 vendor 进仓库,离线可用,见文末「材料与播放方式」)。

依据:docs/TRAINING_PLAN_2026.md《四川大学软件学院 2026 年夏 C/C++ 项目实习 实训方案书 V1.2》「五、执行计划 (二) C++方向」。方案书 C++方向共 10 天, Day6–10 是纯项目实作(学员编码+教员指导+成果展示),没有课堂讲授内容, 不在本教案范围内;本教案覆盖 Day1–5 的全部课堂教学。

0. 受众假设与本轮调整说明(显式声明,供随时纠偏)

本教案假定学员已掌握 C++ 基础语法与面向对象概念,方案书对 Day1 下午的官方 定位就是"C++ 高级程序开发回顾和提升"——复习强化,不是零基础教学。这条假设 不是拍脑袋定的,Day1 模块 B 开始前建议先用 docs/teaching/PRETEST.md(10 题、10 分钟摸底测验)实测一次, 按测验结果决定是照原节奏推进还是回退到语法讲解(该文件里有对应的分层预案)。

与仓库里此前一版教案的关系docs/teaching/ 下此前有一版自定义 4 天教案 (3 天 C++ 强化 + 1 天 Qt,讲:练 ≈ 1:3),是当时按用户选定的另一种日程假设做的。 本版替换那一版,严格对齐官方 10 天方案书 C++ 方向的 Day1–5 结构——差异很 大:官方结构里 C++ 只占 Day1 下午半天(其余 4.5 天都是 Qt),所以 C++ 内容从 原来的 3 天深度压缩为半天的精选亮点 + 自学指针,不再逐章深入;Qt 内容则 从原来压缩的 1 天摊开到 Day2–5 四天,覆盖面明显更广。

内容缺口的显式处理(这是本轮设计的关键决策,写清楚以便后续纠偏):

  • 官方方案书 Day34 提到的 Model/View、JSON 解析、QThread 多线程、 QPropertyAnimation 动画、QStateMachine 状态机,仓库 p03/(wiki 抓取内容) 原本完全没有对应代码。本轮已在 docs/teaching/examples/ 补齐 6 个最小可 运行示例(含配套 README 教学文档),构建已接入根 CMakeLists.txt add_teaching_example 分组,见该文件注释),均已 QT_QPA_PLATFORM=offscreen 离屏验证跑通。这些示例是手工维护的教学补充,不属于 tools/gen_part3.py 的生成产物,重新生成 p01/p03 不会影响它们。
  • 以下两项仍按"纯概念 / 自学"处理,不写可运行代码(原因见括号):
    • Vcpkg 包管理器(Day1)——需要安装真实 vcpkg 工具链,超出"最小示例" 范畴,且与仓库当前依赖面(host gcc/g++ + 隔离 Qt 5.14.2)无关;
    • OpenCV 人脸/目标检测(Day5)——方案书原文本身就标注"可选择",属于 非必修拓展,引入 OpenCV 会新增一条完整的三方库工具链。
    • 如果后续需要这两项也做成可运行示例,请明确提出——这会涉及新增外部依赖, 需要单独确认。

核心概念覆盖原则(本轮追加):此前一版的"讲"部分基本只是代码演示(贴代码 + 一句出处 说明),没有讲透知识点本身的原理。本轮改为:每个"讲"知识点在大纲里至少固定两项——核心 概念(是什么/为什么,不只是怎么写)+ 常见的坑(注意事项/误区),随知识点内联在下面各天 的表格后。这是覆盖清单而非固定讲稿:课堂实际讲解深度按学员反馈现场调整(PRETEST 摸底 好、进度快,可以点到为止;反馈吃力,可以就某个概念多展开几分钟),但大纲必须列全这些点, 以免讲课时漏掉、或降级回退到纯代码演示。幻灯片 day1.htmlday5.html 每个知识点前都配了 对应的"核心概念/常见的坑"卡片(custom.css 里的 .concept-box/.pitfall-box),大纲里的 条目和幻灯片内容一一对应,改一处要同步改另一处。

1. 总体目标

  1. 学员能说出 C++ 相对 C 的关键扩展机制在哪个标准版本成立/失效(复习向, 不重新从语法教起)。
  2. 学员能读懂并扩展一个 Qt 桌面小程序,覆盖信号槽、控件、布局/QSS、事件、 绘图、文件 IO/JSON、Model/View、多线程、动画/状态机中的大多数(覆盖面 是 Qt 教学的重点,深度服从进度)。
  3. 每天结束都有一个可运行、可验证的产出。
  4. 学员能看懂本次实训的项目管理流程(JIRA/Git/OASIS),为 Day610 的项目实作 打基础。

2. 课时结构

每天 6 课时(45 分钟/课时 ×6 = 270 分钟),分两个模块。Day1 上午是开训/职业 素养内容,没有编码练习,用讨论型任务卡代替;其余全部保持"讲:练"结构:

模块 时长 讲授 练习/讨论 小结/答疑
模块 A(上午,3 课时) 135min 35min 95min 5min
模块 B(下午,3 课时) 135min 35min 95min 5min

Day25 讲:练 ≈ 1:2.7;Day1 模块 A 是讨论型任务(不追求"练"的编码产出), 模块 BC++/CMake/Vcpkg)内容压缩,35min 讲授只做"巡礼式"精选亮点。

3. 五天总览

Day 官方主题 模块 A 模块 B
1 开训 + C++回顾/工具链 团队建设/Scrum/C++企业应用(讨论,无编码) C++精选回顾 + CMake实操 + Vcpkg概念
2 Qt开发环境/信号槽/基础控件 项目结构/信号槽 p03/ch0204 控件/布局/QSS美化 p03/ch08 + 新示例 qt_qss_styling → 计算器案例
3 高级控件/事件/文件IO/JSON Model/View 新示例 + 事件拦截 p03/ch09 文件IO p03/ch11 + JSON 新示例 → 本地数据存储案例
4 2D绘图/多线程/动画/状态机 2D绘图 p03/ch10 + QThread 新示例 动画+状态机新示例 → 交互式小游戏案例
5 团队协同/综合案例/OpenCV可选 团队协同开发(概念,用方案书图) 综合案例复盘 + OpenCV/AI 自学指针

标注约定: = 课堂演示讲解, = 学员必须动手完成,参考 = 不在 课堂展开、留作课后自学。所有清单都是精选而非全集。


Day 1 — 开训 + C++ 回顾/工具链

模块 A:团队建设 / 敏捷 Scrum / C++ 在企业中的应用(讨论型,无编码)

讲(35min

内容 素材
团队建设与文化、实训安排与考评要求 口头介绍,无固定素材
项目开发过程管理(JIRA/Git/OASIS/Wiki docs/TRAINING_PLAN_2026.md 「七、质量保证」+ 图 docs/images/training_service_flow.pngquality_four_platforms.png
敏捷 Scrum 项目开发管理 同上「服务流程图」里的迭代环节(需求分析→需求评审→项目研发→阶段评审→项目测试)
C++ 在企业中的应用 口头介绍,结合往届案例(如有)

核心概念与常见误区

  • 实习实训服务流程:概念——需求分析→需求评审→项目研发/代码实现→阶段评审→项目测试/交付, 每环节都有明确"评审"节点把关;误区——把需求分析当走过场,跳过评审直接编码,后期返工成本 远高于前期对齐需求的成本。
  • 四平台一标准:概念——JIRA/Git/Wiki/OASIS 四个工具分别对应"谁在做什么/代码怎么变化/ 知识怎么沉淀/进度怎么被看到"四个维度,缺一个都有协作盲区;误区——只用 Git 不用 Jira,代码 有版本历史但任务分工和进度没有可见记录。

讨论(95min,分组,非编码)

  • 任务卡 1
    • 目标:结合服务流程图,说清楚本组打算怎么分工使用 Jira(任务跟踪)+ Git(代码版本管理)
    • 验收标准:每组提交一句话分工说明(谁负责建 Jira 看板/谁负责 Git 仓库初始化),能在图上指出对应环节
    • 基础知识 · 参考:docs/images/training_service_flow.pngdocs/TRAINING_PLAN_2026.md 「七、质量保证 (一)(二)」
  • 任务卡 2
    • 目标:选定实训期间打算做的项目方向(Linux C 方向 或 C++/Qt 方向的备选商业项目之一)
    • 验收标准:每组报出项目名称 + 一句话说明选择理由
    • 基础知识 · 参考:docs/TRAINING_PLAN_2026.md 「八、备选商业项目介绍」

模块 B:C++ 环境搭建 / 高级程序回顾 / CMake / Vcpkg(压缩讲解)

讲(35min,巡礼式,只挑「学过但容易讲不透」的点,不逐章展开)

知识点 文件 一句话说明
namespace 作用域 p01/ch03/namespace_syntax.cpp 对照 docs/ERRATA.md"作用域"不是"文件顺序"
函数重载决议 p01/ch03/function_overload_mechanism.cpp 名字改写与重载集合,二义性从哪来
引用的本质 p01/ch03/reference_essence.cpp "引用是自动解引用的 const 指针"
虚析构与内存泄漏 p01/ch04/s08/virtual_dtor_purpose.cpp 基类指针 delete 派生类对象的经典坑
模板与 STL 速览 p01/ch05/class_template_basics.cppp01/ch09/s03/vector_iterator.cpp 泛型编程 + 容器/迭代器,只点名不展开
CMake 项目构建 本仓库 CMakeLists.txtp03/CMakeLists.txt 用真实项目当教材:option(BUILD_QT_PART)add_subdirectory、每个示例一个 add_executable 目标
Vcpkg 包管理器(概念,无演示) 无仓库代码 C++ 生态的包管理器,解决"第三方库怎么装、怎么被 CMake 找到"的问题;本仓库用的是"隔离 Qt 手动装"而非 vcpkg,两种思路都要认识

核心概念与常见的坑(每个知识点至少覆盖这两项,课堂讲解深度按学员反馈调整;对应幻灯片 day1.html 每个知识点前的"核心概念/常见的坑"卡片):

  • namespace 作用域:概念——作用域可跨文件延续、跨块合并,不是"文件顺序";坑——头文件里 using namespace std; 会把命名空间污染带给所有 include 它的地方。
  • 函数重载决议:概念——编译器靠名字改写(name mangling)区分重载,二义性源于"同样好"的 候选而非代码写错;坑——隐式类型转换会扩大候选集,可能触发意料之外的重载版本。
  • 引用的本质:概念——"自动解引用的 const 指针"这一视角能解释必须初始化、不能重新绑定; 坑——返回局部变量的引用,函数结束后变成悬空引用。
  • 虚析构与内存泄漏:概念——基类指针 delete 派生类对象时,只有虚析构才会走虚函数表调用到 派生类析构;坑——只要类可能被继承+可能被基类指针删除,就该把析构声明为 virtual。
  • 模板与 STL 速览:概念——泛型编程让代码脱离具体类型复用,迭代器是容器与算法之间的统一 接口;坑——容器扩容/删除元素后旧迭代器可能失效,继续用是未定义行为。
  • CMake 项目构建:概念——CMake 是"生成构建系统的工具"而非构建系统本身,-S -B 生成、 --build 才是真正编译;坑——改了生成器相关配置(换生成器/清缓存)后要重新走一次 -S -B
  • Vcpkg 包管理器:概念——一次 vcpkg install 配合 CMake toolchain 文件,find_package 即可自动定位头文件和库;坑——不是所有第三方库都必须用包管理器装,本仓库选择"隔离 Qt 手动装" 是精确控制版本/路径的另一种取舍,两种思路都要认识。

练(95min

  • 任务卡 1 · 走一遍真实构建流程
    • 目标:独立完成本仓库 Part1 的配置+构建,不看着教师操作
    • 验收标准:cmake -S . -B build -G Ninja -DBUILD_QT_PART=OFF 配置成功;cmake --build build 144 个目标全绿;能说出 option(BUILD_QT_PART) 的作用
    • 基础知识 · 参考:仓库根 CMakeLists.txtCMake 官方文档 Tutorial(选读·需联网)
  • 任务卡 2 · 修一个真实的坑
    • 目标:从 docs/ERRATA.md 挑 2 条记录,在对应源文件里理解"wiki 原文错在哪、现在的写法为什么对"
    • 验收标准:能用一句话向同组同学解释清楚,不能只念代码
    • 基础知识 · 参考:docs/ERRATA.md
  • 任务卡 3(选做)· 版本探针
    • 目标:用 tools/std_probe.py 验证一个标准版本差异点(如三目运算符可否作左值)
    • 验收标准:跑出至少一个"该标准报错、另一个标准不报错"的对比结果,对照 docs/VERSION_NOTES.md §2
    • 基础知识 · 参考:tools/std_probe.pydocs/VERSION_NOTES.md

当日产出验证cmake --build build --target all (Part1) 全绿;每组提交一句话 分工说明 + 至少 1 条 ERRATA 坑点讲解。


Day 2 — Qt 开发环境 / 信号槽 / 基础控件 / 布局与 QSS

模块 A:项目结构 / 第一个程序 / 信号槽

讲(35min

知识点 文件
最小 Qt 程序结构(QApplication + exec() p03/ch02/minimal_qt_app.cpp
控件创建与显示 p03/ch03/button_creation.cpp
内置 / 自定义 / lambda 信号槽 p03/ch04/builtin_signal_slot.cppcustom_signal_slot.cpplambda_signal_slot.cpp

核心概念与常见的坑(对应幻灯片 day2.html 每个知识点前的"核心概念/常见的坑"卡片):

  • 最小 Qt 程序结构:概念——QApplication是唯一的事件循环拥有者,app.exec()阻塞进入 事件循环分发系统事件;Q_OBJECT触发 moc 生成信号槽/属性系统所需的元对象代码;坑——一个 进程只能有一个 QApplication;忘记 exec() 窗口一闪而过;用了信号槽却忘记 Q_OBJECT 会在链接阶段报 undefined reference 且报错不提示"缺宏"。
  • 控件创建与显示:概念——QObject 对象树父子所有权模型,parent 销毁会自动 delete 所有 子对象;坑——忘记传 parent 造成真实内存泄漏;move() 手动定位的控件一旦套上布局会被覆盖。
  • 信号槽(内置/自定义/lambda:概念——观察者模式的 Qt 实现,发送者/接收者彻底解耦; 新语法 &Class::signal 编译期类型检查,旧字符串语法 SIGNAL()/SLOT() 运行时检查;连接 方式分 Direct/Queued/Auto;坑——旧语法写错不报编译错误只是运行时静默连接失败;重载信号 不加 QOverload 消歧义会编译报错。

练(95min

  • 任务卡 1 · 跑通最小程序
    • 目标:编译运行 minimal_qt_appbutton_creation
    • 验收标准:QT_QPA_PLATFORM=offscreen tools/run_qt.sh minimal_qt_appbutton_creation 均退出码为 0,无崩溃
    • 基础知识 · 参考:p03/ch02/minimal_qt_app.cppp03/ch03/button_creation.cpp
  • 任务卡 2 · 自定义信号槽改文本
    • 目标:给一个按钮连接自定义信号槽,点击后改变一个 QLabel 的文本内容
    • 验收标准:编译通过;离屏或有 X 环境下点击/模拟点击后 QLabel 文本确实改变;用 connect 语法而非直接函数调用
    • 基础知识 · 参考:p03/ch04/custom_signal_slot.cpp(主参考)、lambda_signal_slot.cpplambda 槽写法对比)
  • 任务卡 3(选做)· 重载信号消歧义
    • 目标:仿 builtin_signal_slot.cpp,给一个类定义两个同名不同参的信号,用 QOverload 消歧义连接
    • 验收标准:两个重载信号都能各自触发对应的槽
    • 基础知识 · 参考:p03/ch04/builtin_signal_slot.cpp

模块 B:常用控件 / 布局管理 / QSS 界面美化 → 计算器案例

讲(35min

知识点 文件
图片/文本标签控件 p03/ch08/label_pixmap.cpplabel_text_html.cpp
自定义控件与布局(QHBoxLayout p03/ch08/custom_widget.cpp
QSS 界面美化(教学补充) docs/teaching/examples/qss_styling/qt_qss_styling.cpp

核心概念与常见的坑

  • 资源系统 .qrc:概念——:/... 路径是 Qt 资源系统,资源在编译期打包进可执行文件,运行时 不依赖外部文件;坑——.qrc 路径与代码引用不一致会运行时静默失败(不报编译错误);忘记接入 CMake 的 qt5_add_resources/AUTORCC 资源系统不生效。
  • 布局管理(QHBoxLayout:概念——布局管理器接管子控件位置/大小计算,随窗口缩放自动重排; 布局对象也遵循 QObject 父子所有权;坑——同一控件不能属于两个布局;布局设置后又用 setGeometry/move 手动改位置会被下次刷新覆盖。
  • QSS 界面美化:概念——语法脱胎于 CSS(类型/ID 选择器、伪状态)+ 层叠继承规则,作用对象 是 QWidget 树而非 DOM;坑——ID 选择器必须先 setObjectNamesetStyleSheet 会级联影响 所有子控件,范围失控是最容易踩的坑。

练(95min,计算器案例——练习任务,非预建方案)

  • 任务卡 1 · 计算器雏形
    • 目标:组合 button_creation.cpp(多个数字/运算符按钮)+ custom_signal_slot.cpp(点击信号槽)+ custom_widget.cppQGridLayoutQVBoxLayout 排布按钮),做出一个能加减乘除的最小计算器
    • 验收标准:至少支持两个数 + 一种运算符的计算并在 QLabel/QLineEdit 上正确显示结果;界面不重叠、按钮可点击
    • 基础知识 · 参考:p03/ch03/button_creation.cppp03/ch04/custom_signal_slot.cppp03/ch08/custom_widget.cpp
  • 任务卡 2 · 用 QSS 美化计算器
    • 目标:给任务卡 1 的计算器套一份 QSS 样式(数字键/运算键/等号键区分颜色)
    • 验收标准:至少 2 类按钮有不同的 background-color;至少 1 个按钮有 :hover:pressed 效果
    • 基础知识 · 参考:docs/teaching/examples/qss_styling/qt_qss_styling.cppREADME

当日产出验证:现场演示计算器(QT_QPA_PLATFORM=offscreen tools/run_qt.sh <target> 或有 X 环境直接运行),至少完成一次正确运算 + QSS 美化。


Day 3 — 高级控件与 Model/View / 事件机制 / 文件 IO 与 JSON

模块 AModel/View 架构 / 事件机制

讲(35min

知识点 文件
Model/View 模型视图架构(教学补充) docs/teaching/examples/model_view/qt_model_view_basics.cpp
事件循环机制(复用 Day2 概念) p03/ch02/minimal_qt_app.cppapp.exec()
自定义事件处理 / 事件过滤器 p03/ch09/event_override_customwidget.cppevent_filter_mainwindow.cpp
鼠标事件 p03/ch09/mouse_event.cpp

核心概念与常见的坑(对应幻灯片 day3.html):

  • Model/View 架构:概念——数据(QAbstractItemModel)与展示(QListView/QTableView 彻底拆开,同一模型可喂给多个视图;QModelIndex + 角色(Qt::DisplayRole等)统一寻址; 坑——改模型数据不发 dataChanged/beginInsertRows 信号,视图不会自动刷新。
  • 事件循环:事件 vs 信号:概念——app.exec() 事件循环分发 QEvent(复用 Day2);事件是 框架推给控件的通知,信号槽是对象间主动通知,两者不同机制;坑——主线程做耗时操作会卡住整个 事件循环(呼应 Day4 QThread)。
  • 自定义事件处理 / 事件过滤器:概念——两条拦截路径:重写 xxxEvent()(只影响自己)或 installEventFilter()(统一拦截多个控件);事件有 accept()/ignore() 状态决定是否继续 传播;坑——重写事件函数忘记调用基类实现,会丢失控件默认行为。

练(95min

  • 任务卡 1 · Model/View 换视图
    • 目标:把 qt_model_view_basics.cpp 里的 QListView 换成 QTableView,模型代码不改
    • 验收标准:编译通过,界面正常展示同一份数据,证明"同一个模型可以喂给不同视图"
    • 基础知识 · 参考:docs/teaching/examples/model_view/qt_model_view_basics.cppREADME
  • 任务卡 2 · 事件过滤器实操
    • 目标:仿 event_filter_mainwindow.cpp,给一个控件装事件过滤器,拦截鼠标按下事件并打印坐标
    • 验收标准:点击控件后终端/调试输出能看到坐标信息
    • 基础知识 · 参考:p03/ch09/event_filter_mainwindow.cppmouse_event.cpp

模块 B:文件 IO / JSON 解析 → 本地数据存储案例

讲(35min

知识点 文件
文本文件读写 p03/ch11/qfile_basic.cppqtextstream_io.cpp
结构化二进制读写 p03/ch11/qdatastream_io.cpp
JSON 解析与写入(教学补充) docs/teaching/examples/json_io/qt_json_parse_write.cpp

核心概念与常见的坑

  • QIODevice 统一读写抽象:概念——QFile/QTextStream/QDataStream 都建立在 QIODevice 统一接口上,之后遇到网络/串口等设备也是同一套接口;QTextStream面向文本行、QDataStream 面向结构化二进制;坑——忘记检查 open() 返回值会静默失败;混淆文本/二进制模式会破坏内容。
  • JSON 序列化/反序列化:概念——序列化/反序列化是一对互逆操作,正确性标准是"写出去再读 回来数据一致"round-trip);QJsonValue 是能装多种类型的变体;坑——不检查 QJsonParseError 会让格式错误的输入静默变成空文档;类型不匹配 toInt()/toString() 不报错只返回默认值。

练(95min,本地数据存储案例——练习任务,非预建方案)

  • 任务卡 1 · JSON 落盘
    • 目标:把 qt_json_parse_write.cpp 的 JSON 数据实际写入一个文件(结合 qfile_basic.cppQFile 写法),再读回来解析校验
    • 验收标准:程序运行后磁盘上生成一个 .json 文件,内容可读;重新运行程序能正确解析出之前写入的数据
    • 基础知识 · 参考:docs/teaching/examples/json_io/qt_json_parse_write.cppREADMEp03/ch11/qfile_basic.cpp
  • 任务卡 2 · 本地数据存储小工具
    • 目标:设计一个"学员信息"结构(姓名/成绩/标签),支持增加一条记录并追加保存到 JSON 文件,重启程序后能读出之前保存的全部记录
    • 验收标准:至少能存 2 条以上记录并在重启后完整读回;数据字段不丢失
    • 基础知识 · 参考:docs/teaching/examples/json_io/p03/ch11/qtextstream_io.cpp

当日产出验证:现场演示本地数据存储小工具,验证"写入 → 重启 → 读回"完整闭环。


Day 4 — 2D 图形绘制 / 多线程 / 动画框架与状态机

模块 A2D 绘图 / 多线程

讲(35min

知识点 文件
QPainter 基础绘图 p03/ch10/qpainter_basic.cpp
绘图设备(QImage/QPixmap/QPicture p03/ch10/paint_device_qimage.cpppaint_device_pixmaps.cppqpicture_io.cpp
QThread 多线程(教学补充) docs/teaching/examples/qthread_worker/qt_thread_worker.cpp

核心概念与常见的坑(对应幻灯片 day4.html):

  • QPainter 绘图:概念——Qt 绘制是框架驱动而非"想画就画",所有绘制只能发生在 paintEvent 里,由 Qt 按需自动调用;主动触发重绘要用 update()(异步排队);坑——在 paintEvent 之外直接画东西是未定义行为;数据变了忘记 update()界面不会自动重画。
  • QThread 多线程:概念——线程亲和性(每个 QObject 归属于创建/moveToThread到的线程, GUI 控件必须归属主线程);官方推荐 worker-object 模式而非继承 QThread;跨线程信号槽自动 变 Queued,无需手动加锁;坑——在工作线程直接操作 GUI 控件是未定义行为/崩溃常见来源; moveToThread要在connectstart()之前完成。

练(95min

  • 任务卡 1 · 画一个简单图形界面
    • 目标:仿 qpainter_basic.cpp,在 paintEvent 里画一个组合图形(如棋盘格/仪表盘刻度)
    • 验收标准:编译通过,离屏或 X 环境下能看到图形正确绘制(可截图验证)
    • 基础知识 · 参考:p03/ch10/qpainter_basic.cpp
  • 任务卡 2 · 感受多线程不卡界面
    • 目标:把 qt_thread_worker.cpp 里的耗时计算换成一个更长的循环或 QThread::msleep,观察主线程/事件循环没有被卡住
    • 验收标准:能说清楚"如果把这段计算直接放主线程会发生什么"(界面无响应),并解释 moveToThread 起的作用
    • 基础知识 · 参考:docs/teaching/examples/qthread_worker/qt_thread_worker.cppREADME

模块 B:动画框架 / 状态机 → 交互式小游戏案例

讲(35min

知识点 文件
QPropertyAnimation 动画(教学补充) docs/teaching/examples/property_animation/qt_property_animation.cpp
QStateMachine 状态机(教学补充) docs/teaching/examples/state_machine/qt_state_machine.cpp

核心概念与常见的坑

  • QPropertyAnimation 动画:概念——动画建立在属性系统(Q_PROPERTY,同样靠 moc 生成) 上,本质是"用缓动曲线在一段时间内不断调用属性的 setter",任何 Q_PROPERTY 都能被动画驱动; 坑——属性必须是真正的 Q_PROPERTY,随手传错属性名不会报错只是什么也不发生;动画作用对象 在播放完成前被销毁会导致悬空访问。
  • QStateMachine 状态机:概念——让"状态"成为一等对象(QState),替代一堆 bool 标志位加 if-else;状态转移(addTransition)本质是信号触发的转移,与信号槽自然衔接;坑——忘记 setInitialStatestart(),状态机对象存在但从未真正运行;状态未覆盖所有触发条件会导致 "卡住"。

练(95min,交互式小游戏案例——练习任务,选做,非预建方案)

  • 任务卡 1 · 动画 + 状态机组合
    • 目标:把 qt_property_animation.cpp 的动画和 qt_state_machine.cpp 的状态切换组合到同一个窗口——例如按钮在"红灯"状态时禁止移动,"绿灯"状态时点击才触发动画
    • 验收标准:状态切换正确(红灯不触发动画,绿灯触发动画);动画播放完整不报错
    • 基础知识 · 参考:docs/teaching/examples/property_animation/docs/teaching/examples/state_machine/
  • 任务卡 2(选做)· 简易反应力小游戏
    • 目标:结合任务卡 1 + 鼠标事件(Day3 mouse_event.cpp+ 多线程计时(Day4 qt_thread_worker.cpp),做一个"状态变化后限时点击"的最小交互游戏
    • 验收标准:游戏至少有"开始→进行中→结束"三个可辨识状态,计时或计分逻辑不崩溃
    • 基础知识 · 参考:上述三个教学补充示例 + p03/ch09/mouse_event.cpp

当日产出验证:分组演示动画+状态机组合小工具(任务卡 2 选做,量力而行)。


Day 5 — 团队协同开发 / 综合案例复盘 / OpenCV(可选自学)

模块 A:团队协同开发(概念讲解)

讲(35min

内容 素材
项目开发过程管理全景(JIRA + Git + WIKI + 钉钉直播) docs/images/training_service_flow.png
质量保证体系(四平台一标准) docs/images/quality_four_platforms.png
标准化考核标准 docs/images/assessment_standard.png
代码团队协同开发实操建议 docs/TRAINING_PLAN_2026.md 「七、质量保证 (二) Git」

核心概念与常见误区(对应幻灯片 day5.html):

  • Git 提交习惯:概念——每完成一个任务都提交代码并写清任务描述,提交粒度对应 Jira 任务 粒度,commit 信息是可追溯记录;误区——攒几天代码一次性提交、commit 信息写"update",历史 记录失去可追溯性。
  • 标准化考核标准:概念——项目管理评估(40%)+项目技术评估(30%)+职业素养评估(30%),技术 只占三成;误区——只顾埋头写代码、忽略项目管理和职业素养维度,另外 70% 权重被拉低。

讨论(95min

  • 任务卡 1 · 分工复盘
    • 目标:结合考核标准图(项目管理评估/项目技术评估/职业素养评估三大块),对照 Day1 任务卡 1 定下的分工,检查执行情况
    • 验收标准:每组能说出至少 1 项做得好的、1 项需要改进的
    • 基础知识 · 参考:docs/images/assessment_standard.png

模块 B:综合案例复盘 + OpenCV/AI(可选,自学指针)

讲(35min

内容 说明
Day24 案例回顾 请 1–2 组现场展示计算器/本地存储/动画状态机小游戏
OpenCV 与 AI 机器学习(可选,自学指针,无配套代码) 方案书原文标注"可选择";如学员感兴趣,自学方向为 cv::CascadeClassifier 人脸检测入门,OpenCV 官方教程(需联网,选读)

核心概念与常见误区

  • 案例回顾:概念——代码走查(code review)是团队协作常规环节,讲清"为什么这么设计"比 "功能能跑"更能体现对 Day2–4 核心概念的理解;误区——只演示能跑不讲为什么,观摩组提不出有效 问题,复盘失去巩固概念的作用。
  • OpenCV 与 AI(可选):概念——OpenCV 是独立于 Qt 的计算机视觉库,Qt 管界面/交互、 OpenCV 管图像算法,两者通过 cv::MatQImage 转换配合。

练(95min,综合演练)

  • 任务卡 1 · 三选一深化
    • 目标:从计算器 / 本地数据存储 / 动画状态机小游戏中选一个继续深化(加一个新功能)
    • 验收标准:现场演示新增功能正常工作,编译无报错
    • 基础知识 · 参考:回顾 Day2–4 对应的教学补充示例与 README

当日产出验证:每组现场演示深化后的案例,教师按考核标准图三大块给出反馈, 为 Day6–10 的正式项目实作分组定方向。


4. 验证与考核方式

  • 每天结束前 10 分钟:学员提交当天任务卡的产出文件,用 cmake --build build 验证 Qt 相关目标需先 -DBUILD_QT_PART=ON -DCMAKE_PREFIX_PATH=$PWD/.qt514/5.14.2/gcc_64)。
  • Day5 结束:三选一深化案例的现场演示,作为 Day1–5 阶段的考核点,同时对齐 方案书「标准化的考核标准」三大评估维度(项目管理/项目技术/职业素养)。
  • 教师侧参考答案:仓库已有的 p03/ 文件和 docs/teaching/examples/ 里的教学 补充示例都是可运行的正确版本,可直接用作评分参照;docs/ERRATA*.md 记录了 每一处 wiki 原文修正,可用于讲解"错在哪、对在哪"。

5. 材料与播放方式

  • 大纲:本文件 docs/teaching/OUTLINE.md
  • 交互幻灯片:docs/teaching/slides/day1.htmlday5.htmlindex.html 为入口页。
  • 教学补充示例:docs/teaching/examples/,6 个最小可运行 Qt 程序 + README, 构建方式见根 CMakeLists.txtdocs/teaching/examples 一节;运行方式与 p03/ 里的示例一致:QT_QPA_PLATFORM=offscreen tools/run_qt.sh <target>
  • 技术方案:reveal.js 5.2.1(仅 dist/ 核心 + plugin/highlight)已 vendor 进 docs/teaching/slides/reveal/零 CDN 依赖,断网教室也能播放。任务卡里的 <span class="ext-ref"> 标注的官方文档/外部教程是选读项,需要联网才能 打开,不影响幻灯片本身离线播放。
  • 播放方式(代码链接用相对路径指向仓库源文件,需要 HTTP 而非 file:// 才能正常跳转):
    cd /home/charles/workspaces/qt-course
    python3 -m http.server 8000
    # 浏览器打开 http://localhost:8000/docs/teaching/slides/index.html
    
  • 幻灯片内所有「文件」链接均为相对本仓库路径的可点击链接,点开后由浏览器直接展示 源码(配合上面的 http.server);教师也可直接在编辑器里打开同一路径带学员精读。