每个「讲」知识点补齐核心概念 + 常见的坑,幻灯片与大纲同步
此前一版「讲」部分基本只是代码演示(贴代码 + 一句出处说明),没有讲透 知识点本身的原理。改为覆盖清单原则:每个知识点在大纲里至少固定两项—— 核心概念(是什么/为什么,不只是怎么写)+ 常见的坑(注意事项/误区), 课堂实际讲解深度按学员反馈现场调整,但大纲必须列全,以免漏讲或退化成 纯代码演示。 - custom.css 新增 .concept-box/.pitfall-box 卡片样式 - day1–5.html 每个知识点前插入对应卡片,内容与 OUTLINE.md 的覆盖清单一一对应
This commit is contained in:
@@ -74,6 +74,35 @@
|
||||
}
|
||||
.verify-box h4 { margin: 0 0 6px 0; color: #b7791f; }
|
||||
|
||||
/* 每个「讲」知识点的固定两件套:核心概念(是什么/为什么)+ 常见的坑(注意事项) */
|
||||
.concept-box {
|
||||
border-left: 6px solid #2b6cb0;
|
||||
background: #ebf4ff;
|
||||
padding: 12px 22px;
|
||||
margin: 10px 0;
|
||||
border-radius: 4px;
|
||||
text-align: left;
|
||||
font-size: 0.58em;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.concept-box h4 { margin: 0 0 6px 0; color: #2b6cb0; }
|
||||
.concept-box ul { margin: 4px 0 0 20px; padding: 0; }
|
||||
.concept-box li { margin: 3px 0; }
|
||||
|
||||
.pitfall-box {
|
||||
border-left: 6px solid #c53030;
|
||||
background: #fff5f5;
|
||||
padding: 12px 22px;
|
||||
margin: 10px 0;
|
||||
border-radius: 4px;
|
||||
text-align: left;
|
||||
font-size: 0.58em;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.pitfall-box h4 { margin: 0 0 6px 0; color: #c53030; }
|
||||
.pitfall-box ul { margin: 4px 0 0 20px; padding: 0; }
|
||||
.pitfall-box li { margin: 3px 0; }
|
||||
|
||||
.reveal pre code { font-size: 0.68em; max-height: 480px; }
|
||||
|
||||
.module-badge {
|
||||
|
||||
+147
-23
@@ -47,20 +47,52 @@
|
||||
|
||||
<section>
|
||||
<h3>实习实训服务流程 <span class="tag tag-lecture">讲</span></h3>
|
||||
<img src="../../images/training_service_flow.png" style="max-height:480px;">
|
||||
<img src="../../images/training_service_flow.png" style="max-height:520px;">
|
||||
<p><small>出处:<a class="filelink" target="_blank"
|
||||
href="../../TRAINING_PLAN_2026.md">docs/TRAINING_PLAN_2026.md</a>
|
||||
「六、实习实训服务流程」——需求分析→需求评审→项目研发/代码实现→阶段评审→
|
||||
项目测试/交付,这就是接下来 Day6–10 项目实作要走的完整流程。</small></p>
|
||||
href="../../TRAINING_PLAN_2026.md">docs/TRAINING_PLAN_2026.md</a> 「六、实习实训服务流程」</small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>服务流程:核心概念 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>需求分析→需求评审→项目研发/代码实现→阶段评审→项目测试/交付——每个环节都有明确的
|
||||
"评审"节点把关,不是写完代码就结束,这就是接下来 Day6–10 项目实作要走的完整流程。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见误区</h4>
|
||||
<ul>
|
||||
<li>把"需求分析"当成走过场:跳过评审直接开始编码,后期返工成本远高于前期多花时间对齐需求。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>质量保证:四平台一标准 <span class="tag tag-lecture">讲</span></h3>
|
||||
<img src="../../images/quality_four_platforms.png" style="max-height:420px;">
|
||||
<img src="../../images/quality_four_platforms.png" style="max-height:520px;">
|
||||
<p><small>出处:<a class="filelink" target="_blank"
|
||||
href="../../TRAINING_PLAN_2026.md">docs/TRAINING_PLAN_2026.md</a>
|
||||
「七、质量保证」——JIRA(任务跟踪)+ Git(版本管理)+ Wiki 知识库 +
|
||||
OASIS 绿洲实训管理平台,是接下来项目实作阶段的四个协作工具。</small></p>
|
||||
href="../../TRAINING_PLAN_2026.md">docs/TRAINING_PLAN_2026.md</a> 「七、质量保证」</small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>四平台一标准:核心概念 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>JIRA(任务跟踪)+ Git(版本管理)+ Wiki 知识库 + OASIS 绿洲实训管理平台,四个工具
|
||||
分别对应"谁在做什么/代码怎么变化/知识怎么沉淀/进度怎么被看到"四个不同维度,缺一个都会
|
||||
让协作出现盲区。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见误区</h4>
|
||||
<ul>
|
||||
<li>只用 Git 不用 Jira:代码有了版本历史,但"谁负责什么、进度到哪"没有可见记录,
|
||||
团队协作时容易重复劳动或漏项。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -112,8 +144,21 @@
|
||||
|
||||
<section>
|
||||
<h3>namespace 作用域 <span class="tag tag-lecture">讲</span></h3>
|
||||
<p>"作用域"不是"文件顺序"——很多人误以为 namespace 只是给名字加前缀,
|
||||
实际上它定义的是一段可以被跨文件延续、跨块合并的作用域。</p>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>"作用域"不是"文件顺序"——很多人误以为 namespace 只是给名字加前缀,实际上它定义的是
|
||||
一段可以被跨文件延续、跨块合并的作用域,同一个命名空间可以在多个文件里反复打开、追加内容。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>在头文件里写 <code>using namespace std;</code>:会把整个命名空间污染带给所有
|
||||
include 这个头文件的地方,容易引发命名冲突,规范做法是只在 .cpp 里用,或干脆不用、
|
||||
全程写限定名。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p><small>出处:<a class="filelink" target="_blank"
|
||||
href="../../../p01/ch03/namespace_syntax.cpp">p01/ch03/namespace_syntax.cpp</a>,
|
||||
对照 <a class="filelink" target="_blank" href="../../ERRATA.md">docs/ERRATA.md</a></small></p>
|
||||
@@ -121,16 +166,40 @@
|
||||
|
||||
<section>
|
||||
<h3>函数重载决议 <span class="tag tag-lecture">讲</span></h3>
|
||||
<p>编译器靠"名字改写"(name mangling)把重载函数变成不同的符号;二义性
|
||||
往往不是代码写错了,而是重载集合里存在两个"一样好"的候选。</p>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>编译器靠"名字改写"(name mangling)把重载函数变成不同的符号;二义性往往不是代码写
|
||||
错了,而是重载集合里存在两个"一样好"的候选,编译器无法替你选。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>隐式类型转换会扩大重载候选集——比如 <code>int</code>/<code>double</code> 都能转
|
||||
<code>float</code> 参数,传一个 <code>long</code> 进去可能触发意料之外的重载版本。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p><small>出处:<a class="filelink" target="_blank"
|
||||
href="../../../p01/ch03/function_overload_mechanism.cpp">p01/ch03/function_overload_mechanism.cpp</a></small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>引用的本质 <span class="tag tag-lecture">讲</span></h3>
|
||||
<p>把引用理解成"自动解引用的 const 指针"——这个实现视角能解释引用为什么
|
||||
必须初始化、为什么不能重新绑定。</p>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>把引用理解成"自动解引用的 const 指针"——这个实现视角能解释引用为什么必须初始化、
|
||||
为什么不能重新绑定到另一个对象。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>返回局部变量的引用:函数结束局部变量已销毁,返回的引用变成悬空引用,后续访问是
|
||||
未定义行为——和返回局部变量指针是同一类坑。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p><small>出处:<a class="filelink" target="_blank"
|
||||
href="../../../p01/ch03/reference_essence.cpp">p01/ch03/reference_essence.cpp</a></small></p>
|
||||
</section>
|
||||
@@ -141,14 +210,41 @@
|
||||
Base* p = new Derived();
|
||||
delete p; // 如果 ~Base() 不是 virtual,~Derived() 不会被调用——经典泄漏
|
||||
</code></pre>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>通过基类指针 <code>delete</code> 派生类对象时,只有基类析构函数是 <code>virtual</code>
|
||||
才会走虚函数表找到派生类的析构函数——这是"多态"在析构这个场景下的具体体现。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>只要一个类可能被继承、且可能通过基类指针删除派生对象,就应该把析构函数声明为
|
||||
<code>virtual</code>——即使当前基类本身没什么要清理的,这是个防御性约定。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p><small>出处:<a class="filelink" target="_blank"
|
||||
href="../../../p01/ch04/s08/virtual_dtor_purpose.cpp">p01/ch04/s08/virtual_dtor_purpose.cpp</a></small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>模板与 STL 速览 <span class="tag tag-lecture">讲</span></h3>
|
||||
<p>只点名,不展开:泛型编程(函数模板/类模板)+ 容器/迭代器,是 Day6–10
|
||||
项目实作里会大量用到的基础设施。</p>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>只点名,不展开:泛型编程(函数模板/类模板)让同一份代码适配不同类型,容器/迭代器
|
||||
是 Day6–10 项目实作里会大量用到的基础设施——迭代器是"容器和算法之间的统一接口",这也是
|
||||
STL 能让算法脱离具体容器类型复用的关键。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>容器扩容/删除元素后,之前保存的迭代器可能失效(如 <code>vector</code> 扩容),
|
||||
继续用失效的迭代器是未定义行为——遍历中增删元素前要先弄清对应容器的迭代器失效规则。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p><small>出处:<a class="filelink" target="_blank"
|
||||
href="../../../p01/ch05/class_template_basics.cpp">p01/ch05/class_template_basics.cpp</a>、
|
||||
<a class="filelink" target="_blank" href="../../../p01/ch09/s03/vector_iterator.cpp">p01/ch09/s03/vector_iterator.cpp</a></small></p>
|
||||
@@ -158,19 +254,47 @@ delete p; // 如果 ~Base() 不是 virtual,~Derived() 不会被调用——
|
||||
<h3>CMake:用本仓库当教材 <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="bash" data-trim>cmake -S . -B build -G Ninja -DBUILD_QT_PART=OFF -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build build # 144 个目标全绿</code></pre>
|
||||
<p><small>出处:仓库根 <a class="filelink" target="_blank" href="../../../CMakeLists.txt">CMakeLists.txt</a>——
|
||||
<code>option(BUILD_QT_PART)</code> 控制是否编译 Qt 部分,每个示例一个
|
||||
<code>add_executable</code> 目标,这就是"一文件一目标"约定的由来。</small></p>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>CMake 是"生成构建系统的工具"而不是构建系统本身:<code>cmake -S -B</code> 读
|
||||
<code>CMakeLists.txt</code> 生成 Ninja/Makefile 工程,<code>cmake --build</code> 才是
|
||||
真正编译。<code>option(BUILD_QT_PART)</code> 控制是否编译 Qt 部分,每个示例一个
|
||||
<code>add_executable</code> 目标,这就是"一文件一目标"约定的由来。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>改了 <code>CMakeLists.txt</code> 却没重新 <code>cmake</code> 配置(只 <code>build</code>):
|
||||
大多数改动 CMake 会自动侦测重新配置,但换了生成器/清了缓存等情况需要重新走
|
||||
<code>-S -B</code> 一次。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p><small>出处:仓库根 <a class="filelink" target="_blank" href="../../../CMakeLists.txt">CMakeLists.txt</a></small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Vcpkg 包管理器(概念,无演示) <span class="tag tag-lecture">讲</span></h3>
|
||||
<p>C++ 生态的包管理器,解决"第三方库怎么装、怎么被 CMake 找到"的问题。</p>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>C++ 生态的包管理器,解决"第三方库怎么装、怎么被 CMake 找到"的问题——一次
|
||||
<code>vcpkg install</code>,配合 CMake 的 toolchain 文件,<code>find_package</code>
|
||||
就能自动找到头文件和库。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>不是所有第三方库都必须用包管理器装——本仓库用的是"隔离 Qt 手动装"
|
||||
(<code>tools/install_qt_host.sh</code>)而非 vcpkg,两种思路都要认识:包管理器省心但
|
||||
引入额外工具链,手动隔离装则精确控制版本/路径,各有取舍。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="verify-box">
|
||||
<h4>缺口说明</h4>
|
||||
<p>本仓库用的是"隔离 Qt 手动装"(<code>tools/install_qt_host.sh</code>)
|
||||
而非 vcpkg,两种思路都要认识;本仓库暂无 vcpkg 可运行示例——安装真实
|
||||
vcpkg 工具链超出最小示例范畴,此处仅作概念介绍。</p>
|
||||
<p>本仓库暂无 vcpkg 可运行示例——安装真实 vcpkg 工具链超出最小示例范畴,此处仅作概念介绍。</p>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -42,6 +42,30 @@ cmake --build build</code></pre>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>最小 Qt 程序:核心概念 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li><code>QApplication</code> 是整个进程唯一的"事件循环拥有者"——<code>app.exec()</code>
|
||||
阻塞在这里进入事件循环,不断从操作系统取事件(鼠标/键盘/定时器/重绘请求)分发出去,
|
||||
程序的"活着"就是这个循环在转,不是运行完就退出的普通程序。</li>
|
||||
<li><code>Q_OBJECT</code> 宏触发 moc(meta-object compiler)在编译前生成额外代码——
|
||||
信号槽、属性系统、<code>qobject_cast</code> 等运行时反射能力都靠这份生成代码实现,
|
||||
这是 Qt 自己的预处理步骤,不是普通 C++ 语法。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>一个进程只能有一个 <code>QApplication</code> 实例,创建第二个直接崩溃/未定义行为。</li>
|
||||
<li>忘记调用 <code>exec()</code>:窗口一闪而过就退出,因为根本没进入事件循环。</li>
|
||||
<li>类里用了信号槽却忘记写 <code>Q_OBJECT</code>:编译能过,链接阶段报
|
||||
<code>undefined reference</code>——报错信息完全不提示"缺宏",是新手最常踩的坑。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>最小 Qt 程序:QApplication + exec() <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
@@ -63,6 +87,28 @@ int main(int argc, char* argv[]) {
|
||||
<code>QTimer::singleShot</code> 200ms 自动退出,便于离屏自动化验证,真实项目不需要这一行)</small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>控件创建:对象树与父子所有权 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>QObject 有一套"对象树"父子所有权模型:给控件传入 <code>parent</code> 后,
|
||||
parent 被销毁时会自动 <code>delete</code> 所有子对象——这就是为什么 Qt 代码里到处是
|
||||
<code>new</code> 却几乎不见 <code>delete</code>。</li>
|
||||
<li>两种写法(先构造后设属性 / 构造时一次性传参)本质相同,父对象的作用一样。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>忘记传 <code>parent</code>:控件永远不会自动释放(真实内存泄漏),也不会自动出现在
|
||||
窗口里(没有父容器就没有布局位置)。</li>
|
||||
<li>用 <code>move()</code> 手动摆放坐标的控件,一旦外层套上布局管理器,手动坐标会被
|
||||
布局在下次刷新时覆盖——这是"混用绝对定位和布局"最常见的诡异 bug 来源。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>控件创建:两种写法 <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
@@ -79,6 +125,32 @@ QPushButton* btn2 = new QPushButton(QStringLiteral("孙悟空"), this);
|
||||
href="../../../p03/ch03/button_creation.cpp">p03/ch03/button_creation.cpp</a></small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>信号槽:观察者模式 + moc <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>信号槽本质是"观察者模式"的 Qt 实现:发送者不知道、也不关心谁在监听,彻底解耦发送方
|
||||
和接收方——这和"直接调用某个函数"是完全不同的设计取向。</li>
|
||||
<li><code>connect()</code> 背后依赖 moc 生成的元对象信息做类型检查:新语法
|
||||
<code>&Class::signal</code> 是<strong>编译期</strong>检查,字符串旧语法
|
||||
<code>SIGNAL()/SLOT()</code> 是<strong>运行时</strong>检查,容易悄悄连接失败。</li>
|
||||
<li>连接方式分 Direct(同线程直接调用)/ Queued(跨线程排队,下次事件循环处理)/
|
||||
Auto(默认,同线程 Direct、跨线程自动 Queued)——<a class="filelink" target="_blank"
|
||||
href="day4.html">Day4</a> 讲 QThread 时还会用到。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>旧的字符串语法 <code>SIGNAL(clicked())</code> 函数名/参数类型写错不会编译报错,
|
||||
只会运行时"连接失败"且经常没有提示——能用新语法就不用旧语法,编译期就能发现问题。</li>
|
||||
<li>重载信号(如右侧例子的两个 <code>hungry()</code>)不加 <code>QOverload</code>
|
||||
消歧义,编译器不知道该连哪个重载,直接报错。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>信号槽:内置 / 自定义 / 重载消歧义 <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
@@ -160,6 +232,27 @@ connect(t, QOverload<QString>::of(&Teacher::hungry), s, QOverload<QStri
|
||||
<h2>常用控件 / 布局管理 / QSS 美化 <span class="tag tag-lecture">讲</span></h2>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>资源系统:.qrc 是什么 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li><code>:/Image/boat.jpg</code> 这种路径不是文件系统路径,是 Qt 资源系统(QRC)——
|
||||
图片等资源在编译期被打包进可执行文件本身,运行时不依赖外部文件是否存在,这对
|
||||
"打包发布"很关键。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li><code>.qrc</code> 里资源路径/文件名和代码里 <code>:/...</code> 引用的不一致,会在
|
||||
运行时静默失败(<code>QPixmap</code> 为空、图不显示),不会报编译错误。</li>
|
||||
<li>忘记把 <code>.qrc</code> 接入 CMake 的 <code>qt5_add_resources</code>/AUTORCC,
|
||||
资源系统压根不生效。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>常用控件:QLabel 显示图片 <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
@@ -173,6 +266,28 @@ label->setPixmap(pixmap);
|
||||
HTML 富文本标签见 <a class="filelink" target="_blank" href="../../../p03/ch08/label_text_html.cpp">label_text_html.cpp</a></small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>布局管理:为什么不手算坐标 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>布局管理器(<code>QLayout</code>)接管子控件的位置和大小计算,随窗口缩放自动重新
|
||||
排布——这是"不要自己算坐标"的根本原因,也是跨平台/跨分辨率 UI 能正确显示的基础。</li>
|
||||
<li>布局对象本身也遵循 QObject 父子所有权:<code>new QHBoxLayout(this)</code>
|
||||
把布局设为 <code>this</code> 的布局,同时隐式接管了 <code>addWidget</code> 进来的子控件。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>同一个控件不能同时属于两个布局,重复 <code>addWidget</code> 到不同布局会导致界面
|
||||
异常或崩溃。</li>
|
||||
<li>布局设置之后又用 <code>setGeometry</code>/<code>move</code> 手动改控件位置,效果
|
||||
会被布局在下次刷新时覆盖(呼应上一节"控件创建"的坑)。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>自定义控件与布局:QHBoxLayout <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
@@ -190,6 +305,29 @@ connect(slider, &QSlider::valueChanged, spin, &QSpinBox::setValue);
|
||||
不用手算控件坐标。</small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>QSS:类 CSS 的样式层叠 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>QSS 语法脱胎于 CSS:选择器(类型选择器 <code>QPushButton</code>、ID 选择器
|
||||
<code>#okButton</code>、伪状态 <code>:hover</code>/<code>:pressed</code>)+ 属性声明,
|
||||
但作用对象是 QWidget 树而不是 DOM。</li>
|
||||
<li>样式表遵循层叠规则:作用在父控件上的样式默认会被子控件继承,除非子控件有自己更
|
||||
具体的规则覆盖。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>用 ID 选择器(<code>#okButton</code>)必须先 <code>setObjectName("okButton")</code>,
|
||||
忘记设置会导致规则完全不生效且没有任何报错。</li>
|
||||
<li>在某个容器上 <code>setStyleSheet</code> 会级联影响它所有子控件(包括不想改的),
|
||||
范围失控是 QSS 最容易踩的坑,通常要用更具体的选择器限定范围。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>QSS 界面美化(教学补充) <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
|
||||
@@ -30,6 +30,30 @@
|
||||
<h2>Model/View 架构 / 事件机制 <span class="tag tag-lecture">讲</span></h2>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Model/View:数据与展示分离 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>Model/View 把"数据"和"怎么展示数据"彻底拆开:模型(<code>QAbstractItemModel</code>
|
||||
及其子类)只负责存数据、回答"这个位置是什么",视图(<code>QListView</code>/
|
||||
<code>QTableView</code>/...)只负责画——同一份模型可以同时喂给多个不同视图。</li>
|
||||
<li>模型用统一的 <code>QModelIndex</code>(行/列/父项)寻址数据,视图向模型要数据时
|
||||
还要带上"角色"(<code>Qt::DisplayRole</code> 显示文本、<code>Qt::DecorationRole</code>
|
||||
图标……),同一个位置可以按不同角色返回不同内容。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>直接改模型内部数据却不发信号(<code>dataChanged</code>/<code>beginInsertRows</code>+
|
||||
<code>endInsertRows</code>),视图不会自动刷新,界面和数据"对不上"。</li>
|
||||
<li>用了简单的 <code>QStandardItemModel</code> 却又想自定义复杂数据结构:应该继承
|
||||
<code>QAbstractItemModel</code> 自己实现,而不是硬塞进 Item 模型。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Model/View 模型视图架构(教学补充) <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
@@ -50,6 +74,31 @@ connect(view->selectionModel(), &QItemSelectionModel::currentChanged, ...);
|
||||
仓库 <code>p03/</code> 的 wiki 抓取内容没有 Model/View,这是本轮补写的教学补充示例,已离屏验证跑通。</small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>事件循环:事件 vs 信号 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li><code>app.exec()</code> 进入的就是事件循环(复用
|
||||
<a class="filelink" target="_blank" href="day2.html">Day2</a> 概念)——鼠标点击、
|
||||
键盘输入、定时器触发都会变成"事件"(<code>QEvent</code>),被塞进这个循环里依次分发给
|
||||
对应控件。</li>
|
||||
<li>事件和信号是两条不同的机制:事件是"操作系统/框架推给控件"的通知,走
|
||||
<code>event()</code>/<code>xxxEvent()</code> 虚函数或事件过滤器;信号槽是"对象之间"
|
||||
主动通知,走 <code>connect()</code>。控件收到事件后,常见做法就是在事件处理函数里
|
||||
<code>emit</code> 一个信号,把"底层事件"转成"业务语义通知"。</li>
|
||||
<li>今天讲的"事件过滤器"就是在事件被分发给控件之前,插一个"拦截点"。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>在事件循环所在的主线程做耗时操作会直接卡住整个界面(无法重绘、按钮点了没反应)——
|
||||
这也是 <a class="filelink" target="_blank" href="day4.html">Day4</a> 要讲 QThread 的原因。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>事件循环机制(复用 Day2 概念) <span class="tag tag-lecture">讲</span></h3>
|
||||
<p><code>app.exec()</code> 进入的就是事件循环——鼠标点击、键盘输入、定时器
|
||||
@@ -59,6 +108,29 @@ connect(view->selectionModel(), &QItemSelectionModel::currentChanged, ...);
|
||||
href="../../../p03/ch02/minimal_qt_app.cpp">p03/ch02/minimal_qt_app.cpp</a></small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>自定义事件处理:核心概念 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>拦截事件有两条路:重写 <code>xxxEvent()</code>(只影响这一个控件自己)或装事件过滤器
|
||||
<code>installEventFilter()</code>(可以在事件到达目标控件之前,由另一个对象统一拦截,
|
||||
常用于"一个地方管多个控件"的场景)。</li>
|
||||
<li>事件对象有 <code>accept()</code>/<code>ignore()</code> 状态:处理完事件要表明"我
|
||||
吃掉了这个事件"还是"继续往上传",决定事件是否会继续传播给父控件。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>重写 <code>xxxEvent()</code> 时忘记调用基类实现(如 <code>QWidget::mouseMoveEvent</code>),
|
||||
可能丢失控件本身需要的默认行为。</li>
|
||||
<li>事件过滤器安装到一个对象上后,如果被观察对象先于过滤器对象销毁(或反过来),要注意
|
||||
生命周期——Qt 会在对象销毁时自动清理,但过滤逻辑里持有的裸指针不会自动清空。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>自定义事件处理 / 事件过滤器 <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
@@ -123,6 +195,29 @@ protected:
|
||||
<h2>文件 IO / JSON 解析 <span class="tag tag-lecture">讲</span></h2>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>QIODevice:统一的读写抽象 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li><code>QFile</code>/<code>QTextStream</code>/<code>QDataStream</code> 都建立在
|
||||
<code>QIODevice</code> 这一统一读写接口上——同样的"打开/读/写/关闭"套路,以后遇到网络
|
||||
套接字/串口一类设备也是同一套接口,学一次可以迁移到别的设备类型。</li>
|
||||
<li><code>QTextStream</code> 面向"文本行"(人可读),<code>QDataStream</code> 面向
|
||||
"结构化二进制"(保留类型信息,程序间高效互传但人不可直接读)——按需求选,不是谁更好。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>忘记检查 <code>open()</code> 的返回值:文件不存在/无权限时静默失败,后续读写在一个
|
||||
没打开的设备上操作,容易读出空数据而不报错。</li>
|
||||
<li>混淆文本模式和二进制模式(<code>QIODevice::Text</code>):文本模式下 Qt 会做换行符
|
||||
转换,用来读写二进制数据会破坏内容。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>文件系统:QFile 读文本 <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
@@ -136,6 +231,29 @@ while (!file.atEnd()) { qDebug() << file.readLine(); }
|
||||
<a class="filelink" target="_blank" href="../../../p03/ch11/qdatastream_io.cpp">qdatastream_io.cpp</a></small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>JSON:序列化与反序列化的往返 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>JSON 读写的本质是"内存对象 ↔ 文本"的一对互逆操作:序列化(<code>QJsonDocument::toJson</code>)
|
||||
把内存数据变成可存/可传的文本,反序列化(<code>fromJson</code>)再变回来——正确性的标准是
|
||||
"写出去再读回来,数据要一致"(round-trip)。</li>
|
||||
<li><code>QJsonValue</code> 是一个变体(variant)类型,能装字符串/数字/布尔/数组/对象,
|
||||
取值时要按预期类型调用 <code>toString()</code>/<code>toInt()</code> 等。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>忘记检查 <code>QJsonDocument::fromJson</code> 的 <code>QJsonParseError</code>:
|
||||
文本格式错误时返回一个空文档,后续取值全是默认值,不会崩溃也不会报错,很难定位。</li>
|
||||
<li>类型不匹配时 <code>toInt()</code>/<code>toString()</code> 等不会抛异常,只会静默
|
||||
返回默认值(0/空串),排查时容易误以为"数据没写进去"。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>JSON 解析与写入(教学补充) <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
|
||||
@@ -30,6 +30,30 @@
|
||||
<h2>2D 绘图 / 多线程 <span class="tag tag-lecture">讲</span></h2>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>QPainter:由 Qt 驱动的重绘模型 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>Qt 的绘制是"框架驱动"而非"你想画就画":所有绘制只能发生在 <code>paintEvent</code>
|
||||
里,由 Qt 在需要重绘时(窗口刚显示、被遮挡后重新露出、你主动请求)自动调用——这和直接式
|
||||
绘图(想画就立刻画到屏幕)是不同的模型。</li>
|
||||
<li>控件想主动触发重绘要调用 <code>update()</code>(异步,排队到下次事件循环处理)而不是
|
||||
直接调用 <code>paintEvent()</code>;<code>QPainter</code> 只是"在哪个设备上画"的画笔,
|
||||
画布可以是控件本身,也可以是 <code>QImage</code>/<code>QPixmap</code> 等离屏设备。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>在 <code>paintEvent</code> 之外的地方直接 <code>new QPainter(this)</code> 画东西:
|
||||
要么无效要么未定义行为,绘制必须在 <code>paintEvent</code> 回调期间进行。</li>
|
||||
<li>数据变了却忘记调用 <code>update()</code>:界面不会自动感知"要重画了",看起来像是
|
||||
"画错了",其实是"根本没重画"。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>绘图:QPainter <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
@@ -48,6 +72,33 @@ void paintEvent(QPaintEvent*) override {
|
||||
<a class="filelink" target="_blank" href="../../../p03/ch10/paint_device_pixmaps.cpp">paint_device_pixmaps.cpp</a></small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>QThread:线程亲和性与 worker-object <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>"线程亲和性"(thread affinity):每个 QObject 都归属于创建它/被
|
||||
<code>moveToThread</code> 移动到的那个线程,它的槽函数默认在所属线程执行——GUI 控件必须
|
||||
始终归属主线程,这是 Qt 线程模型的核心约束。</li>
|
||||
<li>官方推荐的是 worker-object 模式(把耗时逻辑放进一个普通 QObject,
|
||||
<code>moveToThread</code> 到工作线程),而不是继承 <code>QThread</code> 重写
|
||||
<code>run()</code>——前者能继续用信号槽通信,后者容易把线程亲和性搞混。</li>
|
||||
<li>跨线程的信号槽连接会自动变成 Queued(回顾
|
||||
<a class="filelink" target="_blank" href="day2.html">Day2</a>),结果通过事件循环
|
||||
安全地"带回"接收者所在线程,不需要手动加锁。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>在工作线程里直接操作 GUI 控件(比如直接 <code>label->setText()</code>):Qt 的 GUI
|
||||
模块不是线程安全的,这是未定义行为/崩溃的常见来源——正确做法永远是发信号,排队回主线程处理。</li>
|
||||
<li><code>moveToThread</code> 要在 <code>connect</code> 和 <code>thread.start()</code>
|
||||
之前完成;对象一旦有耗时任务在跑,中途再挪线程会有竞态。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>QThread 多线程(教学补充) <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
@@ -117,6 +168,32 @@ connect(&workerThread, &QThread::started, &worker, &Worker::process);
|
||||
<h2>动画框架 / 状态机 <span class="tag tag-lecture">讲</span></h2>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>QPropertyAnimation:动画建立在属性系统上 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>Qt 的属性系统(<code>Q_PROPERTY</code>,同样靠
|
||||
<a class="filelink" target="_blank" href="day2.html">Day2</a> 讲过的 moc 生成)给每个属性配了
|
||||
统一的 get/set 接口;动画框架的本质就是"在一段时间内,用缓动曲线不断调用某个属性的
|
||||
setter",所以任何声明成 <code>Q_PROPERTY</code> 的属性(不只是内置的 geometry/opacity)
|
||||
都能被动画驱动。</li>
|
||||
<li><code>QEasingCurve</code> 决定的是"数值随时间变化的曲线形状"(线性/回弹/加减速……),
|
||||
动画本身只是"定时器 + 插值 + 调 setter"的组合,理解这点能解释为什么几乎所有属性都能做动画。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>要动画化的属性必须是真正的 <code>Q_PROPERTY</code>(有 setter),随手传一个字符串
|
||||
属性名如果对应类没有声明该属性,动画不会报错,只是什么也不会发生。</li>
|
||||
<li>动画作用的对象在动画播放完成前被销毁会导致悬空访问;
|
||||
<code>QAbstractAnimation::DeleteWhenStopped</code> 能让动画结束后自动释放自身,但不管
|
||||
目标对象的生命周期,目标对象仍需自己保证不提前销毁。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>QPropertyAnimation 动画(教学补充) <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
@@ -132,6 +209,31 @@ anim->start(QAbstractAnimation::DeleteWhenStopped);
|
||||
(<a class="filelink" target="_blank" href="../examples/property_animation/README.md">配套 README</a>)</small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>QStateMachine:状态机建立在信号槽上 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>状态机解决的是"同一个控件在不同状态下行为/外观不同"的问题——与其用一堆
|
||||
<code>bool</code> 标志位加 if-else 判断当前处于什么状态,不如让"状态"本身成为一等对象
|
||||
(<code>QState</code>),每个状态自己声明"进入这个状态要怎样"(<code>assignProperty</code>,
|
||||
又用到了 Qt 属性系统)。</li>
|
||||
<li>状态之间的切换(<code>addTransition</code>)本质是"信号触发的转移"——转移条件就是
|
||||
一个信号,这让状态机和信号槽自然衔接:任何能发信号的事件都能驱动状态切换。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见的坑</h4>
|
||||
<ul>
|
||||
<li>忘记 <code>machine.setInitialState(...)</code> 或忘记调用 <code>machine.start()</code>:
|
||||
状态机对象存在但从未真正运行,所有 <code>assignProperty</code>/<code>addTransition</code>
|
||||
都不会生效。</li>
|
||||
<li>某个状态没有覆盖所有可能触发的信号/条件,会导致状态机"卡住"——设计状态机前先把所有
|
||||
状态和转移条件画成图,比直接写代码更不容易漏。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>QStateMachine 状态机(教学补充) <span class="tag tag-lecture">讲</span></h3>
|
||||
<pre><code class="cpp" data-trim data-noescape>
|
||||
|
||||
@@ -34,20 +34,52 @@
|
||||
|
||||
<section>
|
||||
<h3>质量保证:四平台一标准(复习) <span class="tag tag-lecture">讲</span></h3>
|
||||
<img src="../../images/quality_four_platforms.png" style="max-height:420px;">
|
||||
<img src="../../images/quality_four_platforms.png" style="max-height:520px;">
|
||||
<p><small>出处:<a class="filelink" target="_blank"
|
||||
href="../../TRAINING_PLAN_2026.md">docs/TRAINING_PLAN_2026.md</a>
|
||||
「七、质量保证 (二) Git」——接下来 Day6–10 项目实作,每人每完成一个任务都要提交代码
|
||||
到 Git 并写清任务描述。</small></p>
|
||||
href="../../TRAINING_PLAN_2026.md">docs/TRAINING_PLAN_2026.md</a> 「七、质量保证 (二) Git」</small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Git 提交习惯:核心概念 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>接下来 Day6–10 项目实作,每人每完成一个任务都要提交代码到 Git 并写清任务描述——
|
||||
提交粒度对应 Jira 任务粒度,commit 信息就是"这次提交做了什么、为什么"的可追溯记录。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见误区</h4>
|
||||
<ul>
|
||||
<li>攒了几天代码一次性提交、commit 信息写"update":历史记录失去可追溯性,出问题时无法
|
||||
定位是哪次改动引入的。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>标准化考核标准 <span class="tag tag-lecture">讲</span></h3>
|
||||
<img src="../../images/assessment_standard.png" style="max-height:480px;">
|
||||
<img src="../../images/assessment_standard.png" style="max-height:520px;">
|
||||
<p><small>出处:<a class="filelink" target="_blank"
|
||||
href="../../TRAINING_PLAN_2026.md">docs/TRAINING_PLAN_2026.md</a>
|
||||
「七、(五) 标准化的考核标准」——项目管理评估(40%) + 项目技术评估(30%) +
|
||||
职业素养评估(30%),Day6–10 项目实作最终按这个标准打分。</small></p>
|
||||
href="../../TRAINING_PLAN_2026.md">docs/TRAINING_PLAN_2026.md</a> 「七、(五) 标准化的考核标准」</small></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>考核标准:核心概念 <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>项目管理评估(40%) + 项目技术评估(30%) + 职业素养评估(30%)——技术实现只占三成,
|
||||
Day6–10 项目实作最终按这三个维度综合打分,不是"代码能跑就满分"。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见误区</h4>
|
||||
<ul>
|
||||
<li>只顾埋头写代码、忽略项目管理和职业素养维度(如任务跟踪是否及时更新、沟通是否
|
||||
到位):技术分再高,另外 70% 的权重会明显拉低总评。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -83,10 +115,31 @@
|
||||
<section>
|
||||
<h3>Day2–4 案例回顾 <span class="tag tag-lecture">讲</span></h3>
|
||||
<p>请 1–2 组现场展示计算器 / 本地数据存储 / 动画状态机小游戏,其他组观摩提问。</p>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>代码走查(code review)是团队协作的常规环节——展示时讲清"为什么这么设计"比"功能能跑"
|
||||
更能体现对 Day2–4 核心概念(对象树/信号槽/Model-View/线程亲和性……)的理解程度。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pitfall-box">
|
||||
<h4>常见误区</h4>
|
||||
<ul>
|
||||
<li>只演示"能跑"不讲"为什么":观摩组提不出有效问题,复盘就失去了巩固概念的作用。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>OpenCV 与 AI 机器学习(可选,自学指针) <span class="tag tag-lecture">讲</span></h3>
|
||||
<div class="concept-box">
|
||||
<h4>核心概念</h4>
|
||||
<ul>
|
||||
<li>OpenCV 是独立于 Qt 的计算机视觉库,Qt 负责界面/交互,OpenCV 负责图像算法——两者通过
|
||||
"内存里的图像数据格式转换"(<code>cv::Mat</code> ↔ <code>QImage</code>)配合,是很多
|
||||
桌面视觉类项目的典型组合方式。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="verify-box">
|
||||
<h4>缺口说明</h4>
|
||||
<p>方案书原文对本项标注"可选择",属于非必修拓展。引入 OpenCV 会新增一条完整的
|
||||
|
||||
Reference in New Issue
Block a user