0f81edcc74
- 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 失效
255 lines
12 KiB
HTML
255 lines
12 KiB
HTML
<!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:30–11:00 讲 / 11:00–12:00 练):QMainWindow · 对话框 QDialog</li>
|
||
<li>下午(13:30–16:00 讲 / 16:00–17:00 作业):布局管理器 · 常用控件 · QSS 美化</li>
|
||
</ul>
|
||
<p><small>今天的主线:把昨天的计算器升级成"正经软件"——主窗口骨架 + 对话框交互 +
|
||
布局讲透 + 美化。</small></p>
|
||
</section>
|
||
|
||
<!-- ===================== 上午:讲 ===================== -->
|
||
<section>
|
||
<section>
|
||
<p class="module-badge">上午 · 讲授 08:30–11: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:30–16: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>
|