Qt学习之路94章知识地图:信号槽、事件、model/view与线程复习指南

发布时间:2026/10/24 11:14:41
Qt学习之路94章知识地图:信号槽、事件、model/view与线程复习指南 简介这份《QT学习之路2-2020整理版》面向希望系统掌握Qt框架的开发者从零基础入门到进阶实战均可参考。内容整理自豆子博客在原有79章基础上补全了2016年3月后更新的15章共94章涵盖Qt简介、信号槽机制、自定义信号槽、MainWindow、布局管理器、事件处理、对话框数据传递等核心主题并延伸至多线程、国际化、数据库集成与网络编程等高级方向同时涉及Qt Creator使用与调试技巧。资源为1个PDF文件压缩包约5.79MB目录结构完整、章节编号清晰便于按主题顺序学习或跳转查阅。目前已有870人学习适合需要一份体系化Qt5与Qt Creator学习材料、希望从基础概念一路推进到项目实践的读者收藏研读。1. Qt 学习之路的完整知识地图94 章到底覆盖了什么很多人第一次翻开《Qt 学习之路 2》的目录第一反应是“怎么这么多章”——94 章、445 页从 Hello world 一路排到 QML 组件。但真正梳理下来会发现它并不是零散知识点的堆叠而是一条从 C 框架认知到 GUI 编程、再到模型视图、网络、线程、QML 的完整链路。这份 2020 整理版把原博客 79 章之后的内容补齐到 94 章等于把 Qt 5 时代最核心的入门到进阶路径一次性收全了。它适合两类人一类是正在系统学 Qt、需要一张能按图索骥的路线图另一类是已经写过一些 Qt 代码、但知识点在脑子里还是散的想借一份笔记把信号槽、事件、model/view、线程这几条主线重新串起来。下面按模块拆开梳理重点标出复习时最容易卡住的地方。2. 信号槽与事件系统Qt 最核心的两套通信机制2.1 信号槽从旧语法到 Qt5 新语法信号槽是 Qt 区别于其他 C 框架最明显的特征也是面试和实际开发中绕不开的第一道坎。第 4 章到第 6 章、第 16 章集中讲这块。旧语法用SIGNAL()和SLOT()宏本质是字符串匹配编译期不检查参数类型写错了要到运行时才会发现。Qt 5 引入的新语法用函数指针连接编译期就能查出签名不匹配的问题。// 旧语法字符串匹配运行时才报错 connect(sender, SIGNAL(valueChanged(int)), receiver, SLOT(updateValue(int))); // Qt5 新语法编译期检查支持 lambda connect(sender, Sender::valueChanged, receiver, Receiver::updateValue); // 连接 lambda适合一次性逻辑 connect(button, QPushButton::clicked, this, [this]() { // 捕获 this 后可直接访问成员 updateStatus(clicked); });梳理下来会发现新语法最大的价值不是“写法更短”而是把错误从运行时提前到了编译期。参数说明上connect的第五个参数Qt::ConnectionType决定了调用时机AutoConnection是默认值同线程直接调用、跨线程排队QueuedConnection强制排队适合跨线程BlockingQueuedConnection会阻塞发送方只在同线程外使用否则会死锁。最容易忽略的是跨线程用AutoConnection时如果接收者对象的线程亲和性没设置对槽函数仍然会在发送者线程执行这是很多“玄学崩溃”的根源。2.2 事件循环、event() 与事件过滤器第 18 章到第 23 章是事件系统很多人学到这里会觉得“信号槽已经够用了事件是不是可以跳过”——恰恰相反事件是信号槽的底层基础。Qt 的事件循环从QApplication::exec()启动所有窗口消息、定时器、网络回调都在这条循环里分发。QObject::event()是事件分发的总入口mousePressEvent、keyPressEvent这些虚函数只是event()内部按类型转发的分支。bool MyWidget::event(QEvent *e) { if (e-type() QEvent::KeyPress) { // 先做自定义处理再交给基类 auto *ke static_castQKeyEvent *(e); if (ke-key() Qt::Key_Escape) { return true; // 已处理不再传递 } } return QWidget::event(e); // 其余交给默认实现 }事件过滤器installEventFilter是另一个高频考点它让一个对象可以监视另一个对象的事件适合做全局快捷键、输入校验。注意点在于过滤器的eventFilter返回true表示事件被吃掉返回false才会继续传递。最容易翻车的地方是在过滤器里对事件对象做了delete然后又返回false后续处理就会访问野指针。梳理下来事件这块的复习顺序应该是事件循环 →event()分发 → 具体事件函数 → 事件过滤器 → 自定义事件一层层往上叠不要跳。3. GUI 构建主线从 MainWindow 到布局与对话框3.1 MainWindow、动作与资源文件第 7 章到第 12 章是主窗口应用的骨架。QMainWindow比普通QWidget多了菜单栏、工具栏、状态栏和中心部件这几个固定区域。动作QAction是菜单和工具栏共用的抽象一个动作可以同时挂到菜单项和工具按钮上改一处两边同步。资源文件.qrc把图片、图标、翻译文件编进二进制避免运行时路径问题。!-- resources.qrc把图标编进可执行文件 -- RCC qresource prefix/icons filenew.png/file fileopen.png/file /qresource /RCC复习时容易漏的是.qrc里的路径是相对路径前缀prefix决定运行时用:/icons/new.png访问。如果资源没显示先查qmake有没有把.qrc加进RESOURCES再查前缀拼写。另一个易错点是QAction的triggered和toggled信号前者只在用户点击时发出后者在setChecked改变状态时也发出做可勾选动作时要分清。3.2 布局管理器与对话框数据传递第 11 章布局管理器、第 13 到 17 章对话框这两块是实际写界面时用得最多的。布局管理器解决的是“窗口缩放时控件怎么跟着动”核心有QHBoxLayout、QVBoxLayout、QGridLayout、QFormLayout和QStackedLayout。很多人习惯用绝对坐标setGeometry结果换分辨率就乱这是典型的踩坑。布局类适用场景关键参数QHBoxLayout水平排列按钮组stretch 控制拉伸比例QVBoxLayout垂直表单spacing 控制间距QGridLayout行列对齐的复杂面板rowSpan/columnSpan 跨格QFormLayout标签输入框成对出现labelAlignment 对齐方式QStackedLayout多页面切换setCurrentIndex 切页对话框数据传递是另一个高频易错点。模态对话框用exec()阻塞返回QDialog::Accepted或Rejected非模态用show()需要通过信号把数据传回来。标准对话框QMessageBox、QFileDialog、QColorDialog这些在第 15、17 章有专门讲。梳理下来会发现对话框这块的复习重点不是“怎么弹出来”而是“数据怎么安全地传回去”——用信号槽传不要用全局变量也不要直接访问对话框的内部控件。4. 模型视图与数据持久化model/view、文件、数据库、XML/JSON4.1 model/view 架构与自定义模型第 41 章到第 51 章是 model/view这是 Qt 里抽象程度最高、也最容易劝退的一段。核心思想是把数据model、展示view、编辑delegate拆开。QListWidget、QTreeWidget、QTableWidget是便利类内部已经绑好了 model适合小数据量QListView、QTreeView、QTableView配合自定义 model 才能处理大数据和复杂逻辑。// 自定义只读模型的核心rowCount 和 data int MyModel::rowCount(const QModelIndex parent) const { if (parent.isValid()) return 0; // 扁平结构无子节点 return m_items.size(); } QVariant MyModel::data(const QModelIndex index, int role) const { if (!index.isValid()) return {}; if (role Qt::DisplayRole) { return m_items.at(index.row()).name; // 显示文本 } return {}; }参数说明上data()的role决定返回什么DisplayRole是显示文本EditRole是编辑值DecorationRole是图标ToolTipRole是提示。最容易漏的是beginInsertRows/endInsertRows这对调用——不写它们view 不会知道数据变了界面就不刷新。QSortFilterProxyModel是排序过滤的中间层套在源模型和视图之间不用改源模型就能实现搜索。复习时建议按“便利类 → 自定义只读模型 → 自定义可编辑模型 → 代理模型 → 拖放”的顺序过一遍。4.2 文件、数据库与 XML/JSON 处理第 35 到 40 章是文件与容器第 55 到 64 章是数据库和 XML/JSON。文件部分重点在QFile、QTextStream、QDataStream三者的区别QTextStream处理文本编码QDataStream处理二进制且与平台无关。容器部分QList、QVector、QMap、QHash的选型要看访问模式QHash查找平均 O(1) 但不保证顺序QMap按 key 有序但 O(log n)。数据库用QSqlDatabase建立连接QSqlQuery执行 SQL配合QSqlTableModel可以直接把表映射到 view 上。XML 有三种处理方式QXmlStreamReader是流式解析内存占用小DOM 把整棵树读进内存方便随机访问SAX 是事件回调适合超大文件。JSON 用QJsonDocument、QJsonObject、QJsonArray解析和生成都比较直观。// JSON 解析从字符串到对象 QJsonParseError err; auto doc QJsonDocument::fromJson(raw, err); if (err.error ! QJsonParseError::NoError) { // 解析失败err.errorString() 给出原因 return; } auto obj doc.object(); auto name obj.value(name).toString();梳理下来这块的易错点集中在数据库连接名冲突多线程下每个线程要独立连接、XML 编码声明与实际字节不一致、JSON 数字精度丢失大整数用字符串传。这些在项目里都是血泪经验复习时值得单独标出来。5. 网络、进程与线程跨平台应用的进阶模块5.1 网络访问与进程间通信第 65 到 70 章覆盖网络和进程。网络部分QNetworkAccessManager是核心get()、post()返回QNetworkReply通过finished信号拿结果。注意QNetworkReply必须手动deleteLater()否则会内存泄漏。进程部分QProcess可以启动外部程序并读写它的标准输入输出start()之后用waitForStarted()或信号确认状态。// 发起 GET 请求并处理响应 auto *manager new QNetworkAccessManager(this); auto *reply manager-get(QNetworkRequest(QUrl(https://example.com/api))); connect(reply, QNetworkReply::finished, this, [reply]() { if (reply-error() QNetworkReply::NoError) { auto data reply-readAll(); // 读取响应体 } reply-deleteLater(); // 必须释放 });进程间通信除了QProcess还有共享内存QSharedMemory和本地套接字QLocalSocket。选型上父子进程用QProcess最直接同机不同进程用QLocalSocket更灵活。易漏点是QSharedMemory在崩溃后可能残留需要先attach再detach清理。5.2 线程模型与 QObject 的线程亲和性第 71 到 75 章是线程这是 Qt 里最容易出诡异 bug 的地方。QThread本身是一个线程控制对象它对象本身属于创建它的线程真正跑代码的是run()里的内容。推荐用法是moveToThread把工作对象移到子线程通过信号槽跨线程调用而不是继承QThread重写run()。// 推荐worker 对象 moveToThread auto *thread new QThread(this); auto *worker new Worker(); worker-moveToThread(thread); connect(thread, QThread::started, worker, Worker::doWork); connect(worker, Worker::finished, thread, QThread::quit); connect(thread, QThread::finished, worker, QObject::deleteLater); thread-start();参数说明moveToThread之后worker 的槽函数会在子线程执行但前提是连接类型为QueuedConnection或AutoConnection且跨线程。最容易忽略的是QObject的子对象必须和父对象在同一线程跨线程new一个带 parent 的对象会直接报错。线程总结那几章反复强调一句话——不要跨线程直接调用对象方法一律走信号槽。梳理下来线程这块的复习清单就是线程亲和性 → moveToThread → 跨线程信号槽 → 线程安全的数据传递 → 线程退出清理。6. 易漏点与易错点复习时最该盯住的五个地方易漏点一信号槽连接重复。为什么漏connect多次调用同一对信号槽会建立多条连接槽函数被执行多次。怎么补连接前用disconnect清理或者用Qt::UniqueConnection标志或者把连接放在只执行一次的地方。易漏点二事件过滤器返回值的语义。为什么漏eventFilter返回true表示事件被拦截返回false表示继续传递很多人记反。怎么补记住“true 吃掉false 放行”在过滤器里打印日志验证一次。易漏点三model 数据变更没通知视图。为什么漏直接改内部容器没有调用beginInsertRows/dataChanged等信号。怎么补所有数据变更都走 model 提供的接口不要绕过 model 直接改底层数据。易漏点四跨线程访问 GUI。为什么漏子线程里直接调setText、update等 GUI 方法程序随机崩溃。怎么补GUI 操作一律回到主线程用信号槽把结果传回来再更新。易漏点五QNetworkReply 和 QProcess 对象未释放。为什么漏只关注功能实现忘了deleteLater。怎么补在finished信号里统一加deleteLater()形成肌肉记忆。7. 复习清单怎么用这份 94 章笔记查漏补缺复习到后期最怕的是“每章都看过但合上书就串不起来”。我的做法是把 94 章压成一张三层清单每层对应不同的复习动作。第一层是主线层只列六个词信号槽、事件、布局与对话框、model/view、网络与进程、线程。合上书试着对每个词说出它的核心类和典型用法说不出来的就是薄弱模块回去翻对应章节。第二层是接口层把每个模块的高频类和方法列成表对照检查自己是否会用。模块核心类必须会的方法信号槽QObjectconnect / disconnect事件QEventevent / installEventFilter布局QLayoutaddWidget / setStretchmodel/viewQAbstractItemModelrowCount / data / index网络QNetworkAccessManagerget / post / finished线程QThreadmoveToThread / start / quit第三层是易错层就是上一章那五条每次写新代码前扫一眼能避开大部分低级问题。具体操作上我习惯用“三遍法”第一遍按目录顺序通读标记看不懂的章节第二遍只读标记章节配合 Qt Creator 写最小可运行示例第三遍合上资料对着空白文档默写每个模块的核心代码骨架。默写不出来的地方就是真正需要补的地方。这份 2020 整理版把 80 到 94 章补齐之后QML 和 QtQuick 部分也完整了如果你之前只学到 79 章建议把后面这十几章单独过一遍QML 语法、基本元素、组件这三块是 Qt 5 之后界面开发的重要方向。从那以后我每次开始一个新的 Qt 项目都会强制走一遍“主线六词 → 接口表 → 易错五条”的检查确认没有盲区再动手。希望这份梳理能帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询