Files
scuc-qt-course/docs/teaching/slides/day3.html
T
张宗平 0f81edcc74 幻灯片按 4 天版重排:Day1 全 C++、Day3 启用 ch05/ch06、Day5 综合案例
- Day1:开训 + 全天 C++(PRETEST 摸底环节内联;★所有权/★编译 vs 链接错误新卡)
- Day2:Qt 入门 + 信号槽 → 计算器(★栈控件双重释放/★lambda 第五参数/
  ★重复 connect/★QString 中文编码,均链到坑点复现示例)
- Day3:QMainWindow/QDialog(p03/ch05、ch06 首次排课,☆两张新卡)+ 布局/控件/QSS
- Day4:事件/绘图/QTableWidget + 文件系统/JSON(★工作目录/★文件编码)
- Day5:综合案例全天(student_manager 走查 + QThread 提升 + 流程规范)
- index.html 同步 4+1 结构;相对链接脚本校验 0 失效
2026-07-05 12:49:44 +08:00

255 lines
12 KiB
HTML
Raw 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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>Day 3 · QMainWindow / QDialog / 布局与控件 / QSS</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="reveal/reveal.css">
<link rel="stylesheet" href="reveal/theme.css">
<link rel="stylesheet" href="reveal/plugin/highlight/monokai.css">
<link rel="stylesheet" href="custom.css">
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h1>Day 3</h1>
<h3>QMainWindow / 对话框 QDialog / 布局管理器 / 常用控件</h3>
<p class="module-badge">C++/Qt 方向实训 · 第 3 / 4 个讲授日</p>
<ul>
<li>上午(08:3011:00 讲 / 11:0012:00 练):QMainWindow · 对话框 QDialog</li>
<li>下午(13:3016:00 讲 / 16:0017:00 作业):布局管理器 · 常用控件 · QSS 美化</li>
</ul>
<p><small>今天的主线:把昨天的计算器升级成"正经软件"——主窗口骨架 + 对话框交互 +
布局讲透 + 美化。</small></p>
</section>
<!-- ===================== 上午:讲 ===================== -->
<section>
<section>
<p class="module-badge">上午 · 讲授 08:3011:00</p>
<h2>QMainWindow / 对话框 QDialog <span class="tag tag-lecture"></span></h2>
</section>
<section>
<h3>QMainWindow:标准桌面软件的骨架 <span class="tag tag-lecture"></span></h3>
<div class="concept-box">
<h4>核心概念</h4>
<ul>
<li>QMainWindow 不是"大号 QWidget":它有固定的区域布局协议——菜单栏 / 工具栏 /
状态栏 / 停靠窗(dock)各就其位,<b>中心部件必须 <code>setCentralWidget()</code>
显式安放</b>;菜单项和工具栏按钮的统一抽象是 <code>QAction</code>(一个动作,
多处复用)。</li>
</ul>
</div>
<div class="pitfall-box">
<h4>常见的坑</h4>
<ul>
<li>直接往 QMainWindow 上摆控件而不设中心部件——布局行为不可预期;</li>
<li><code>QAction</code> 显示出来 ≠ 生效:忘了 <code>connect</code> 到槽,
就是"菜单点了没反应"。</li>
</ul>
</div>
<p><small>出处:<a class="filelink" target="_blank" href="../../../p03/ch05/central_widget.cpp">p03/ch05/central_widget.cpp</a> ·
<a class="filelink" target="_blank" href="../../../p03/ch05/dock_widget.cpp">dock_widget.cpp</a></small></p>
</section>
<section>
<h3>QDialog:模态与非模态 <span class="tag tag-lecture"></span></h3>
<div class="concept-box">
<h4>核心概念</h4>
<ul>
<li><b>模态</b> <code>exec()</code>:阻塞等用户给结果,返回值就是用户的选择
Accepted/Rejected);<b>非模态</b> <code>show()</code>:立即返回,窗口独立存活
——所以对话框对象必须活过当前函数作用域(堆 + parent,或
<code>WA_DeleteOnClose</code> 自清理)。</li>
<li>标准对话框拿来就用:<code>QMessageBox</code>(提示/确认)、<code>QFileDialog</code>(选文件)。</li>
</ul>
</div>
<div class="pitfall-box">
<h4>常见的坑(昨天的所有权坑第三次出现!)</h4>
<ul>
<li><b>非模态对话框建在栈上</b><code>show()</code> 完函数一返回就析构——窗口一闪而过。
<code>p03/ch06</code> 的三个 modeless 版本(栈/堆/DeleteOnClose)就是这个坑的对照教材。</li>
</ul>
</div>
<p><small>出处:<a class="filelink" target="_blank" href="../../../p03/ch06/modal_dialog.cpp">p03/ch06/modal_dialog.cpp</a> ·
<a class="filelink" target="_blank" href="../../../p03/ch06/modeless_dialog_stack.cpp">modeless_dialog_stack.cpp</a> ·
<a class="filelink" target="_blank" href="../../../p03/ch06/modeless_dialog_heap.cpp">modeless_dialog_heap.cpp</a> ·
<a class="filelink" target="_blank" href="../../../p03/ch06/modeless_dialog_deleteonclose.cpp">modeless_dialog_deleteonclose.cpp</a></small></p>
</section>
<section>
<h3>标准对话框速览 <span class="tag tag-lecture"></span></h3>
<pre><code class="cpp" data-trim data-noescape>
auto ret = QMessageBox::question(this, "确认", "真的要删除吗?");
if (ret == QMessageBox::Yes) { /* ... */ }
QString path = QFileDialog::getOpenFileName(this, "选择文件", "", "*.json");
if (!path.isEmpty()) { /* ... */ } // 用户可能点取消:必须处理空返回
</code></pre>
<div class="pitfall-box">
<h4>常见的坑</h4>
<ul>
<li>不处理"用户点了取消"(空路径/Rejected)就直接往下用——健壮性问题的高发点。</li>
</ul>
</div>
<p><small>出处:<a class="filelink" target="_blank" href="../../../p03/ch06/message_box_question.cpp">p03/ch06/message_box_question.cpp</a> ·
<a class="filelink" target="_blank" href="../../../p03/ch06/message_box_custom.cpp">message_box_custom.cpp</a> ·
<a class="filelink" target="_blank" href="../../../p03/ch06/file_dialog.cpp">file_dialog.cpp</a></small></p>
</section>
</section>
<!-- ===================== 上午:练 ===================== -->
<section>
<section>
<p class="module-badge">上午 · 课堂练习 11:00–12:00(工程师指导、答疑)</p>
<h2>动手:计算器主窗口化 <span class="tag tag-practice"></span></h2>
</section>
<section>
<div class="task-card">
<h4>任务卡 1 · 给计算器套上 QMainWindow <span class="tag tag-practice"></span></h4>
<dl class="task-spec">
<dt>目标</dt>
<dd>把昨天的计算器改造为 QMainWindow 应用:加菜单「帮助→关于」弹
<code>QMessageBox</code>;加一个「历史」停靠窗(可先放空 QLabel)</dd>
<dt>验收标准</dt>
<dd>计算器功能不回退;菜单动作有响应;停靠窗可拖动/收起</dd>
<dt>基础知识 · 参考</dt>
<dd><a class="filelink" target="_blank" href="../../../p03/ch05/central_widget.cpp">p03/ch05/central_widget.cpp</a> ·
<a class="filelink" target="_blank" href="../../../p03/ch05/dock_widget.cpp">dock_widget.cpp</a> ·
<a class="filelink" target="_blank" href="../../../p03/ch06/message_box_question.cpp">p03/ch06/message_box_question.cpp</a></dd>
</dl>
</div>
</section>
</section>
<!-- ===================== 下午:讲 ===================== -->
<section>
<section>
<p class="module-badge">下午 · 讲授 13:3016:00</p>
<h2>布局管理器 / 常用控件 / QSS 美化 <span class="tag tag-lecture"></span></h2>
</section>
<section>
<h3>布局管理器(回收昨天的脚手架) <span class="tag tag-lecture"></span></h3>
<div class="concept-box">
<h4>核心概念</h4>
<ul>
<li>布局管理器接管子控件的位置/大小计算,随窗口缩放自动重排——昨天计算器里"先用后学"
<code>QGridLayout</code> 今天讲透:QHBox/QVBox/QGrid 三兄弟 + 嵌套组合 + 伸缩因子
<code>addStretch()</code>;布局对象同样遵循 QObject 父子所有权。</li>
</ul>
</div>
<div class="pitfall-box">
<h4>常见的坑</h4>
<ul>
<li>同一控件不能属于两个布局;</li>
<li>布局设置后又用 <code>setGeometry()</code>/<code>move()</code> 手动改位置——
会被下次布局刷新覆盖,看起来"设置没生效"。</li>
</ul>
</div>
<p><small>出处:<a class="filelink" target="_blank" href="../../../p03/ch08/custom_widget.cpp">p03/ch08/custom_widget.cpp</a></small></p>
</section>
<section>
<h3>常用控件 + 资源系统 .qrc <span class="tag tag-lecture"></span></h3>
<div class="concept-box">
<h4>核心概念</h4>
<ul>
<li>QLabel 一个控件三种形态:纯文本 / 富文本 HTML / 图片(<code>QPixmap</code>/
动图(<code>QMovie</code>);输入靠 QLineEdit,按钮族 QPushButton/QRadioButton/QCheckBox。</li>
<li><code>:/...</code> 路径是 Qt 资源系统:资源编译期打包进可执行文件,运行时不依赖
外部文件——发布不用带一堆散图。</li>
</ul>
</div>
<div class="pitfall-box">
<h4>常见的坑</h4>
<ul>
<li><code>.qrc</code> 里的路径与代码引用不一致:<b>运行时静默失败</b>(图不显示),
不报编译错误;忘接 CMake 的 AUTORCC/<code>qt5_add_resources</code> 资源系统不生效。</li>
</ul>
</div>
<p><small>出处:<a class="filelink" target="_blank" href="../../../p03/ch08/label_text_html.cpp">p03/ch08/label_text_html.cpp</a> ·
<a class="filelink" target="_blank" href="../../../p03/ch08/label_pixmap.cpp">label_pixmap.cpp</a> ·
<a class="filelink" target="_blank" href="../../../p03/ch08/label_movie.cpp">label_movie.cpp</a></small></p>
</section>
<section>
<h3>QSS 界面美化 <span class="tag tag-lecture"></span></h3>
<pre><code class="css" data-trim>QPushButton#okButton { background-color: #2f855a; border-radius: 6px; }
QPushButton#okButton:hover { background-color: #276749; }</code></pre>
<div class="concept-box">
<h4>核心概念</h4>
<ul>
<li>语法脱胎于 CSS:类型选择器 / ID 选择器(<code>#objectName</code>/ 伪状态
<code>:hover</code> <code>:pressed</code>)+ 层叠继承——作用对象是 QWidget 树而非 DOM
"长什么样"与"做什么"分离,改样式不碰逻辑。</li>
</ul>
</div>
<div class="pitfall-box">
<h4>常见的坑</h4>
<ul>
<li>ID 选择器必须先 <code>setObjectName()</code></li>
<li><code>setStyleSheet()</code> 会级联影响<b>所有子控件</b>——范围失控是最容易踩的坑,
样式尽量写窄(带选择器),不要裸写属性。</li>
</ul>
</div>
<p><small>出处:<a class="filelink" target="_blank"
href="../examples/qss_styling/qt_qss_styling.cpp">examples/qss_styling/qt_qss_styling.cpp</a>
<a class="filelink" target="_blank" href="../examples/qss_styling/README.md">README</a></small></p>
</section>
</section>
<!-- ===================== 下午:作业 ===================== -->
<section>
<section>
<p class="module-badge">下午 · 课堂作业 16:00–17:00(工程师答疑)</p>
<h2>作业:计算器美化升级 <span class="tag tag-practice"></span></h2>
</section>
<section>
<div class="task-card">
<h4>任务卡 2 · 用 QSS 美化计算器 <span class="tag tag-practice"></span></h4>
<dl class="task-spec">
<dt>目标</dt>
<dd>数字键/运算键/等号键用 QSS 区分颜色;整体布局改为随窗口缩放自适应</dd>
<dt>验收标准</dt>
<dd>至少 2 类按钮有不同 <code>background-color</code>;至少 1 个按钮有
<code>:hover</code><code>:pressed</code> 效果;拉伸窗口按钮跟着重排</dd>
<dt>基础知识 · 参考</dt>
<dd><a class="filelink" target="_blank" href="../examples/qss_styling/qt_qss_styling.cpp">examples/qss_styling/</a> ·
<a class="filelink" target="_blank" href="../../../p03/ch08/custom_widget.cpp">p03/ch08/custom_widget.cpp</a></dd>
</dl>
</div>
</section>
</section>
<!-- ===================== 收尾 ===================== -->
<section>
<h2>当日产出验证</h2>
<div class="verify-box">
<h4>验收</h4>
<p>现场演示升级后的计算器:主窗口(菜单/停靠窗)+ QSS 配色 + 缩放自适应,功能不回退。</p>
</div>
<p class="footer-note"><small>钩子 · QSS 与前端 CSS 是同源思想;Qt Designer/QML 是另一条 UI
路线(拖拽/声明式),本课程走纯代码路线,知道它们存在即可。<br>
明天 Day4:事件机制 / 绘图 / 表格 + 文件系统——数据要开始落盘了。</small></p>
<p><a class="filelink" href="index.html">返回目录</a> · <a class="filelink" href="day2.html">← 上一天</a> ·
<a class="filelink" href="day4.html">下一天 →</a></p>
</section>
</div>
</div>
<script src="reveal/reveal.js"></script>
<script src="reveal/plugin/highlight/highlight.js"></script>
<script>
Reveal.initialize({
hash: true, controls: true, progress: true, center: true, slideNumber: true,
plugins: [ RevealHighlight ]
});
</script>
</body>
</html>