2026/10/16 7:43:42

Qt 5.9 C++开发指南:示例源码助你快速上手信号槽与SQLite

Qt 5.9 C++开发指南:示例源码助你快速上手信号槽与SQLite 简介《Qt5.9 C开发指南》PDF及其配套示例源码组成一套完整的Qt学习资料包面向正在学习或进阶Qt的C开发人员帮助读者从环境配置到多线程、网络编程全面上手5.9版本。书中内容涵盖Qt Creator、信号与槽、GUI组件、模型/视图、数据库、国际化等核心主题配套源码则包含简单窗口、网络通信、多线程等可直接运行的示例工程。包体上压缩包共2000个文件大小约311MB主要文件类型包括cpp/h源代码、ui界面文件、pro/qrc工程与资源文件以及大量bmp/jpg/ico图标素材并包含若干个可执行文件和说明PDF整个目录结构与章节对应便于按图索骥。该资源已有22188人学习浏览具有较高的参考价值。通过学习PDF讲解并结合源码动手实践读者可掌握Qt5.9的实际开发流程理解事件驱动与信号槽机制并能在具体工程中熟练运用网络和数据库模块是一份兼顾理论与实战的系统学习资料。1. Qt 5.9 C 开发指南这套 PDF 加示例源码能帮你解决什么接手一个三年前写的 Qt 界面工程界面逻辑清一色 C 信号槽编译环境还停留在 Qt 5.9——这是不少开发者的真实处境。这套资源的核心价值不是让你从头学一遍 C而是拿来即用一本《Qt 5.9 C 开发指南》PDF外加与章节一一对应、能直接编译运行的示例源码工程。从窗口布局、对话框、表格模型到数据库、多线程、TCP 通信每个知识点都配了完整工程。想快速看懂老代码、给现有系统做小改造或者只是想找一套稳定可靠的 Qt Widgets 范式这份材料比零散查文档来得直接。2. 资源全貌PDF 章节与示例源码的映射关系2.1 PDF 指南的章节脉络从最小窗口到网络通信这套 PDF 的组织方式延续了工具书典型的由浅入深结构。第一部分先把 Qt 的工程模型讲透包含.pro文件的关键字段、main函数的写法、QApplication的初始化以及 Qt 中对象树和父子对象的关系。第二部分进入 QWidget 编程逐个展开主窗口、对话框、布局管理器、常用控件的使用。第三部分深入到数据与交互层覆盖模型/视图架构、QPainter绘图、鼠标键盘事件、拖放操作。第四部分聚焦工程能力包括 SQLite 数据库访问、QThread多线程、QTcpSocket与QUdpSocket网络通信、样式表和国际化。值得留意的是PDF 在讲解每个主题时并不是只贴一段代码而是配合“运行效果说明”来讲。也就是说当你打开示例工程、编译运行之后看到界面效果和书中描述一致说明环境没问题如果效果对不上那大概率是某一步改错了或者版本差异导致的这种“代码与描述对照”的读法效率远高于单纯看代码。把 PDF 的目录范围与示例工程对应起来看大致可以这样对照PDF 覆盖范围核心知识点对应示例基础部分.pro 工程、main 入口、对象树、信号槽概念samp1_、samp2_界面部分布局、控件、对话框、主窗口、事件samp3_、samp4_数据部分模型/视图、文件读写、数据库samp5_、samp6_高级部分多线程、网络、样式表、国际化samp7_、samp8_这张表是使用这套资源的索引。遇到“怎么让表格可编辑”这类问题不必从头读 PDF直接定位到数据部分对应的 samp5 系列工程打开代码对照改。2.2 示例源码工程的命名规则samp 前缀背后的知识点索引示例目录里几十个工程命名是有规律的。类似samp2_2这类名字samp表示 sample数字前缀对应 PDF 章节。比如第 1 章的工程是samp1_1、samp1_2第 2 章的是samp2_1、samp2_2以此类推。这个规律在查找代码时特别有用你在书中看到samp4_3想找对应工程直接去源码目录找samp4_3文件夹即可不用靠猜。每个工程内部的组织也很统一。以典型的界面工程为例samp4_3/ ├── samp4_3.pro ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui └── images/ ├── open.png └── save.png.pro是 qmake 的工程描述文件main.cpp承载入口mainwindow.cpp/h是主窗口的实现和声明.ui文件存界面设计数据images目录放菜单和工具栏图标。这种约定俗成的结构让新接手的人能够快速定位界面逻辑在 cpp/h显示布局在 ui构建配置在 pro。理解这个目录结构基本就理解了 Qt Widgets 工程的组织范式。.pro文件里通常还有一段模块声明它是构建时寻找头文件和库的依据QT core gui greaterThan(QT_MAJOR_VERSION, 4): QT widgets TARGET samp4_3 TEMPLATE app SOURCES main.cpp mainwindow.cpp HEADERS mainwindow.h FORMS mainwindow.uiQT widgets是界面程序必须的一项少了它QMainWindow等类的头文件根本找不到。TARGET决定最终生成的 exe 名称SOURCES、HEADERS、FORMS分别列出参与编译的源文件、头文件和.ui文件。示例工程里这几项通常已经写好改工程名或增删文件时需要手动同步这几行否则新加的 cpp 不会被编译运行起来的还是旧逻辑。ui 文件与代码分工是个值得单独说明的点。.ui文件由 Qt Designer 维护双击即可打开可视化编辑但它不会直接参与编译而是由uic工具转换成ui_mainwindow.h。这个文件中的类名是Ui::MainWindow在 cpp 里通过ui-setupUi(this)完成控件创建和布局设置。所以你在 Designer 里拖控件本质上是生成一段构建代码而控制控件行为的逻辑仍然要写在 cpp 里。这套分工贯穿所有示例工程看懂了它就不会再出现“改了 Designer 忘了保存”或“加了控件代码里取不到”的困惑。2.3 技术栈与定位Qt Widgets、qmake 与桌面应用的经典组合这套资源的技术栈清晰且聚焦C 11/14、Qt 5.9 LTS、qmake 构建系统、QWidget和QDialog这套传统桌面组件体系数据库配套QSQLITE驱动。它几乎不涉及 QML 和 Qt Quick属于传统 C 桌面开发路线。它的适用人群很明确。一类是刚接触 Qt 的 C 开发者想通过完整示例理解信号槽、布局、模型/视图这些核心概念另一类是已经在用 Qt 但遇到具体任务需要查写法的开发者——比如要写一个带表格编辑和数据落地的工具直接翻对应的示例工程看就行。对做嵌入式界面、上位机、实验室小工具的开发者来说这套材料更贴近日常开发的实际形态。相比网上碎片化的教程帖子这套资源的优势在于它内部完全自洽PDF 里讲到的每个 API示例里都有能编译的实例而且示例工程的组织方式本来就是按“读代码即可复用”设计的。项目里需要“一个带工具栏的窗口 表格 SQLite 存储”这种组合时直接把对应工程的 mainwindow.cpp 拿出来改比从零写省非常多时间。举个例子某同事接到一个任务给内部工具加一个“从 Excel 导入数据到 SQLite”的功能。他先是上网搜了一堆文章发现写的都是数据库的增删改查没有任何一篇会告诉他怎么把表格界面和数据存储接在一起。后来直接打开这份资源的数据部分示例把表格模型初始化代码和 SQLite 写入代码拼起来再改一下字段名一个下午就做完了。这种“代码块拼接”式的用法比写一篇长篇教程更有实际意义。3. 核心代码拆解信号槽、表模型、数据库与绘图的典型实现3.1 信号与槽三种写法从宏时代到函数指针时代信号槽是 Qt 区别于其它 C 框架的核心机制示例工程里几乎每个界面类都能见到它的身影。先看最早期的宏写法connect(ui-btnOpen, SIGNAL(clicked()), this, SLOT(onBtnOpenClicked()));宏写法的特点是可读性直观SIGNAL和SLOT宏把函数签名转成字符串Qt 在运行时按字符串匹配来建立连接。缺点也在这里信号或槽函数名拼错、参数类型写错编译器完全不管运行时报一句No such slot就可能被忽略最终表现为按钮点了没反应。Qt 5 引入的成员函数指针写法把运行时错误提前到编译期connect(ui-btnOpen, QPushButton::clicked, this, MainWindow::onBtnOpenClicked);第一个参数是信号发送者第二个是信号第三个是接收者对象第四个是槽成员函数。如果MainWindow里不存在onBtnOpenClicked这个成员函数编译直接报错。这在维护老工程时是很好的体检手段把宏写法批量替换成指针写法一次编译就能找出所有连接断点。示例源码里这套写法出现在较新的章节中也适合作为改造模板参考。第三种是 lambda 表达式写法适合槽函数逻辑只有几行的场景connect(ui-lineEditName, QLineEdit::textChanged, this, [this](const QString text) { ui-labelHint-setText(tr(当前输入%1).arg(text)); });留意[this]捕获列表lambda 内部要操作界面控件必须把this捕获进来。tr()是 Qt 的翻译函数项目中文字符串建议都包一层方便日后做国际化。在示例代码里看到这三种写法先区分清楚再判断自己改代码时该用哪一种会省去很多连接失败的排查时间。3.2 模型/视图用 QStandardItemModel 搭一张可编辑表格模型/视图是 Qt 进阶内容的重点示例里最常见的组合是QStandardItemModel配QTableView。下面这段代码在示例工程里很常见用来展示二维数据并允许用户编辑QStandardItemModel *model new QStandardItemModel(this); model-setHorizontalHeaderLabels( {QStringLiteral(姓名), QStringLiteral(部门), QStringLiteral(工号)}); QListQStandardItem * row; row new QStandardItem(QStringLiteral(张三)) new QStandardItem(QStringLiteral(研发部)) new QStandardItem(QStringLiteral(1001)); model-appendRow(row); ui-tableView-setModel(model); ui-tableView-setSelectionBehavior(QAbstractItemView::SelectRows); ui-tableView-setEditTriggers(QAbstractItemView::DoubleClicked);setHorizontalHeaderLabels接收 QStringList 作为列标题appendRow需要的是一个QListQStandardItem*不能直接塞字符串。setSelectionBehavior用来控制选中方式是整行还是单格设置为行选择更符合常见表格操作习惯。setEditTriggers指定双击进入编辑状态示例里有时会演示默认可编辑和锁定编辑两种状态的差异。增删操作对应两个方法model-insertRow(row, 0)在指定位置插入行model-removeRow(index.row())删除行。这里的index来自表格的currentIndex()需要先判断是否有选中行避免 index 无效时调用 removeRow 产生未定义行为。示例里通常在按钮的槽函数里加上if (!ui-tableView-currentIndex().isValid()) return;这类保护这个习惯很值得照抄。3.3 SQLite 文件库打开、建表、参数绑定与事务数据库是示例进阶部分的重头戏Qt 里操作 SQLite 的代码模式高度统一。第一步是添加数据库连接并打开QSqlDatabase db QSqlDatabase::addDatabase(QSQLITE); db.setDatabaseName(demo.db); if (!db.open()) { qDebug() 数据库打开失败 db.lastError().text(); return; }addDatabase的第一个参数是驱动名第二个参数是可选的连接名不传时使用默认连接。SQLite 的setDatabaseName传的是文件路径文件不存在时会自动创建。lastError()返回上一次操作的错误描述排查问题时把它打印出来比瞎猜要快得多。建表和插入用QSqlQueryQSqlQuery query; query.exec(CREATE TABLE IF NOT EXISTS employee ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, department TEXT, salary REAL)); query.prepare(INSERT INTO employee (name, department, salary) VALUES (?, ?, ?)); query.addBindValue(QStringLiteral(李四)); query.addBindValue(QStringLiteral(测试部)); query.addBindValue(8500.0); if (!query.exec()) { qDebug() 插入失败 query.lastError().text(); }prepare里的?是占位符addBindValue依次绑定实际值。这样做的意义不只是防注入更重要的是如果值里包含单引号等特殊字符字符串拼接方式很可能直接把 SQL 语句写坏参数绑定不会出现这种问题。批量插入时示例里会示范用事务提高效率db.transaction(); for (const auto record : records) { query.prepare(INSERT INTO employee (name, department, salary) VALUES (?, ?, ?)); query.addBindValue(record.name); query.addBindValue(record.department); query.addBindValue(record.salary); query.exec(); } db.commit();事务三件套transaction、commit、rollback是批量操作的标配。rollback在出错时需要手动调用示例里通常会配合一个exec返回值的判断失败时打印错误并回滚。实际开发里如果发现批量插入奇慢无比先检查是不是忘了开启事务。3.4 绘图入门QPainter 的基本绘制流程绘图相关的示例多在 PDF 的进阶章节中出现核心类是QPainter。一个标准的重绘流程是继承QWidget并重写paintEventvoid MyWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setPen(QPen(Qt::blue, 2)); painter.setBrush(QBrush(Qt::lightGray)); painter.drawRect(20, 20, 150, 80); painter.drawText(30, 70, QStringLiteral(Hello Qt)); }QPainter painter(this)把当前控件作为绘制设备setRenderHint开启抗锯齿让图形边缘更平滑。setPen设置边界画笔的颜色和线宽setBrush设置填充画刷。drawRect的四个参数分别是左上角 x、y 和宽高drawText的后三个参数是文本的绘制位置。注意Q_UNUSED(event)用来消除编译器对未使用参数的警告这在重写事件函数时很常见。这段代码如果放在示例工程里通常还会配合update()的调用方式来讲刷新机制。控件不会自动重绘要更新画面就得调用update()让它触发一次新的paintEvent。理解了这个机制对后面做动画或者实时数据显示的改动会很有帮助。4. 从源码到窗口在 Windows 上把示例工程跑起来4.1 环境准备Qt 5.9 安装与编译器选择要让示例源码跑起来第一步是装一套与 Qt 5.9 匹配的编译环境。Windows 上通常有两个选择MinGW 32-bit 和 MSVC 2015/2017 64-bit。MinGW 套件自带 GCC 编译器不需要额外安装 Visual StudioMSVC 套件依赖本机已经装好的 VS 版本版本对不上时 Qt Creator 里会提示编译器缺失。我的建议是选择 MinGW理由有三点一是安装体积小环境纯净二是发布时不需要像 MSVC 那样考虑 VC 运行库是否缺失三是 MinGW 环境下的报错信息对新手更友好。安装 Qt 5.9 时组件里勾选对应编译器版本的 Qt 模块和 Qt Creator 即可。如果磁盘空间充裕可以把 msvc 和 mingw 都装上方便切换测试如果只想装一个选 MinGW 准没错。装完之后先验证一下环境在命令行执行qmake --version能看到 qmake 的版本号和 Qt 版本号说明 bin 目录已经正确加入 PATH。这一步没做好的话后面命令行构建会直接报qmake 不是内部或外部命令。4.2 用 Qt Creator 打开示例工程打开 Qt Creator通过菜单选择“打开项目”定位到示例工程目录里的.pro文件。Qt Creator 加载后会弹出一个构建套件选择窗口。这里会自动列出已经安装的套件把 MinGW 套件勾上并配置好编译器路径点击构建按钮即可。第一次构建通常比后续慢因为要生成 Makefile、调用编译器和链接器。如果构建信息栏里出现红色错误先看是编译错误还是链接错误报错信息通常都会指出具体文件和行号点进去就能跳到对应代码。大多数示例工程的代码都是经过验证的构建失败的常见原因其实是套件选错或 Qt 模块没勾全重新检查安装组件比改代码更有效。运行之前还有一个容易忽略的点Qt Creator 默认会把输出目录放在工程目录下的 build 子目录运行时的工作目录也需要正确指定。如果程序运行后找不到数据库文件或资源文件多半是工作目录设置不对。在“项目”运行设置里把工作目录指向 exe 所在目录很多诡异问题就能消失。4.3 命令行构建qmake 与 make 的配合当项目需要自动化构建或者你更喜欢命令行操作时可以手动跑一遍 Qt 工程的完整构建流程。假设示例工程在D:\samples\samp2_2先建一个独立的构建目录mkdir D:\build\samp2_2 cd D:\build\samp2_2 qmake D:\samples\samp2_2\samp2_2.pro mingw32-makeqmake会读取.pro文件生成 Makefilemingw32-make按 Makefile 逐个编译源文件并链接。用 MSVC 套件时最后一步换成nmake。编译完成后可执行文件samp2_2.exe出现在构建目录中。这段流程之所以值得掌握是因为它能帮你绕过图形界面的黑匣子看清每个构建步骤实际做了什么。遇到qmake报错时错误信息里带出的路径和字段能直接定位.pro文件的问题遇到make报错时可以单独重编某个文件而不必全量跑。在后续配置持续集成或者批量编译多个示例工程时这条命令行链路几乎是必走的。4.4 发布目录组装windeployqt 与依赖清单Qt 程序默认依赖多个动态链接库发布到其他机器前必须把依赖补齐。Qt 5.9 自带的windeployqt是打包依赖的标准工具windeployqt D:\build\samp2_2\samp2_2.exe工具会自动分析 exe 的依赖把Qt5Core.dll、Qt5Gui.dll、Qt5Widgets.dll等拷到 exe 目录并创建platforms、imageformats、styles等插件子目录。执行完再看 exe 目录会发现多出了一堆文件和文件夹整个目录拷到任何一台 Windows 机器上都可以直接运行。需要注意windeployqt要使用与编译套件同版本的 bin 目录里的工具MinGW 编译的程序就不要拿 MSVC 版的windeployqt去部署否则可能出现混合运行时库不兼容的问题。部署完以后手动把 exe 从开发机拷贝到一台没有装 Qt 的虚拟机里运行一次是验证打包是否完整的最可靠方法。如果程序里引入了额外的库比如第三方串口库windeployqt不会自动处理此时需要手动把对应的 DLL 一并拷进发布目录。5. 避坑实录Qt 5.9 项目最常见的五个翻车现场5.1 中文乱码源码编码与编译器默认编码不一致现象界面上本该显示“保存成功”结果输出一段乱码或空白。原因Qt 5.9 里源码按 UTF-8 解析但 Windows 下 MSVC 编译器默认按本地代码页GBK读取源文件两边编码不一致导致字符串字面量解析出错中文字符直接变成无法识别的字节序列。解决在.pro里加一行QMAKE_CXXFLAGS /utf-8强制 MSVC 按 UTF-8 处理源文件。如果在 MinGW 环境下通常不会触发这个问题因为 MinGW 默认按 UTF-8 处理。建议项目的所有源文件统一保存为 UTF-8 编码并在.pro中显式声明编码方式这样多人协作时不会因为个人编辑器设置不同而互相踩坑。还有一种补救写法是用QString::fromLocal8Bit()包裹中文字符串但它只适合小范围补丁不宜大面积使用。5.2 ui 文件改了但运行界面没变化现象在 Qt Designer 里拖入一个新按钮并保存.ui回到 Qt Creator 点运行界面上按钮就是不出现。原因.ui文件需要先由uic工具生成对应的ui_xxx.h头文件再参与编译。增量构建时如果没有正确触发 uic旧的ui_xxx.h被继续使用界面就停留在旧状态。另一种情况是ui-setupUi(this)没有被调用或者被放在了某个条件分支后面。解决先执行“清理”再重新构建或者直接删除构建目录后重新构建强制 uic 重跑。同时检查MainWindow构造函数开头是否调用了ui-setupUi(this)此前不要有任何手动创建控件的代码干扰。排查这种问题最快的验证方式是给按钮随便改个属性比如按钮文字看运行后是否生效不生效再按上述路径查。5.3 信号槽连接失败点击按钮没有反应现象按钮点击无响应断点打在槽函数里也不进入程序不报错。原因宏写法connect(ui-btn, SIGNAL(clicked()), this, SLOT(onClicked()))把函数名转成字符串Qt 运行时按名称匹配匹配失败时只在控制台打印一条QObject::connect: No such slot日志很多时候这条日志被隐藏或忽略问题就成了玄学。解决改用函数指针写法connect(ui-btn, QPushButton::clicked, this, MainWindow::onClicked)让编译器在编译期校验槽函数是否存在以及签名是否匹配。同时检查ui-setupUi(this)是否先于 connect 执行以及按钮是否为局部变量——如果按钮是在某个函数里 new 出来的没有指定父对象connect 之后按钮可能已经被释放点击事件的信号也就无从谈起。5.4 SQLite 驱动加载失败QSQLITE driver not loaded现象程序在开发机正常运行拷贝到另一台机器后提示QSqlDatabase: QSQLITE driver not loaded程序退出或数据库功能失效。原因SQLite 驱动qsqlite.dll位于 Qt 的 plugins 目录下发布时没有把它复制到 exe 同级目录程序加载不到插件。开发机上能运行是因为 Qt 安装目录的 plugins 路径在环境中可被找到。解决将 Qt 安装目录下plugins/sqldrivers整个复制到 exe 所在目录并用windeployqt再部署一次。验证驱动是否可用可以在addDatabase之后打印QSqlDatabase::drivers()确认驱动列表中包含 QSQLITE。如果开发环境下驱动列表里都没有它说明安装 Qt 时没勾选 SQLite 模块需要回到安装器补充组件而不是在代码里找原因。5.5 发布后的程序缺 DLL启动即闪退现象exe 双击后窗口一闪而过进程立即结束没有任何提示。原因exe 依赖的某个 Qt DLL 或插件丢失Windows 在进程启动时加载依赖库失败程序直接退出。常见于手动拷贝 exe 而没有同步拷贝 Qt 相关 DLL属于最血的发布踩坑记录。解决用windeployqt补齐依赖后整个目录一起发布。如果已经发布到目标机器才发现问题可以把 exe 放到目标机后用命令行窗口运行系统会弹出对话框或控制台输出提示缺失的 DLL 名称也可以用 Dependencies 这类工具扫描导入表定位差的是哪个库。这类问题大部分是依赖不完整其次才是插件目录位置不对按照“先补齐 DLL、再检查插件目录”的顺序排查通常三轮之内就能定位。6. 二次开发改造把示例程序加工成自己的小工具示例工程里最值得改造的是“表格增删改查”这一类因为它们往往已经把界面与数据的交互逻辑写好了你只需要把数据源换成真实的业务数据。我通常会做三步改造第一把模型初始化的硬编码数据换成从数据库读取第二把增删改按钮对应的槽函数改成实际的 SQL 语句第三把界面文案和列名替换成自己的业务字段。第一步的代码可以这样写void MainWindow::initData() { QSqlQuery query; query.exec(SELECT name, department, salary FROM employee); while (query.next()) { QListQStandardItem * row; row new QStandardItem(query.value(0).toString()) new QStandardItem(query.value(1).toString()) new QStandardItem(query.value(2).toString()); model-appendRow(row); } }query.next()循环里query.value(i)取出当前行第 i 列的值toString()转成字符串放进表格项。这里要注意三列数据的取值顺序必须与 SQL 语句中 select 的列顺序一致否则显示会错位。改造完成后验证顺序是先确认数据库表结构建好再确认表格刷新逻辑最后验证增删改后数据确实写回库中。从那以后我每次拿到示例源码都强制走一遍“先编译能跑、再定位核心代码、最后替换业务数据”的三步流程老项目交接时不再一头雾水。希望这套流程对你也有帮助。本文还有配套的精品资源点击获取