
简介这份PDF文档是面向C开发者整理的Qt5实战范例合集以完整目录版形式覆盖从环境搭建到应用发布的全流程适合刚接触Qt框架、需要按知识点查漏补缺的初中级开发者对照练习。全书共十四章开篇讲解Qt简介、Qt Creator安装与Hello World入门随后依次展开窗体创建与无边框移动、按钮标签文本编辑等常用控件、日历与登录窗口等组件、文件读写、图形图像处理、多媒体、系统与注册表操作、数据库与网络开发、进程线程及数据安全末章给出可执行文件打包与多平台部署思路。资源包仅含1个pdf文件体积约2.84MB章节条目细化到具体控件类名与示例编号方便按目录快速定位。目前已有2459人学习下载可作为Qt5桌面应用开发过程中的速查手册与练习索引。1. 只有目录的 PDF反而更适合当案头手册下载页面上摆着的是一份“完整目录版”PDF翻开不是成段讲解而是十四章节的范例清单第 1 章开发环境第 2 章窗体应用第 3 章控件应用一路排到第 14 章打包部署中间夹着文件操作、图形图像、多媒体、系统操作、注册表、数据库、网络、进程与线程、数据安全。第一次翻会有点失落——条目多正文薄。但做 Qt5 C 这行久了会发现这种结构的价值恰恰不在“读完”在“按索引取用”手上有个老项目要改标题栏图标、要拖一个无边框窗口、要往 INI 里塞配置、要连一个 SQLite 库翻到对应条目照着参数改十分钟能见效。它适合三类人维护存量 Qt5 工程的开发者、需要快速补齐 GUI 这一环的后端或嵌入式工程师、以及带学生做课程设计时需要一份“能力边界清单”的人。真正反直觉的地方是目录本身就是需求池你先看目录能干什么再决定要不要啃正文比从头读到尾省太多时间。2. 环境与工程骨架把 Qt5 MinGW 这套组合先跑通翻这份手册第一个拦路虎不是代码是环境。原书基于 Qt 5.1.1 的 32 位 MinGW 版本这个组合放到今天依然能跑但构建套件、编码、插件路径三件事没对齐后面所有范例都是空谈。我的习惯是先把一个空工程编译成功、能弹出窗口、能改标题再去碰第 2 章往后的东西不然出了问题分不清是环境还是代码。2.1 三基类怎么选QMainWindow、QWidget、QDialog 的分工手册第 2 章第一节就点到了三个基类很多人扫一眼就跳过结果写到一半发现主窗口没有状态栏、或者对话框关不掉。这三个类的边界其实很清楚基类典型场景需要注意QMainWindow带菜单栏、工具栏、状态栏的主窗口中央部件要用 setCentralWidget 挂上去直接 addWidget 不生效QWidget自定义控件、无边框窗口、嵌入式面板最轻什么都要自己搭包括关闭按钮QDialog登录框、设置页、短任务交互有 exec() 模态循环和返回值别拿它当主窗口选型判断我一般用一句话这个窗口需不需要常驻、需不需要菜单栏。需要常驻且有菜单QMainWindow只是弹一下拿个结果QDialog剩下的全用 QWidget。手册里“登录窗口”那节用的是对话框思路“移动无边框窗体”用的是 QWidget 思路两个范例放在一起看选型逻辑就出来了。有一个容易踩的点QMainWindow 的布局不能直接 setLayout必须 new 一个中央部件再 setCentralWidget。新手在这里卡住的现象是窗口一片空白代码没报错怎么也找不到原因。2.2 一个最小可复现工程main.cpp 与 .pro 骨架不管后面复现哪个范例工程骨架都长一个样。下面这三段是每次新建项目时我都会核对一遍的尤其是 .pro它决定了你能不能用到 sql、network、multimedia 这些模块。// main.cpp —— 程序入口顺序不能乱 #include mainwindow.h #include QApplication int main(int argc, char *argv[]) { QApplication a(argc, argv); // 必须先构造后面所有 QWidget 都依赖它 MainWindow w; // 构造主窗口此时还没显示 w.show(); // 真正映射到屏幕 return a.exec(); // 进入事件循环不写这行窗口一闪就没 }// mainwindow.cpp —— 第 2 章所有窗体范例的公共起点 #include mainwindow.h #include QLabel MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { this-setWindowTitle(Qt5 窗体应用); // 标题后面改图标也挂在这 this-resize(400, 300); // 初始尺寸别和最大最小尺寸混用 QLabel *label new QLabel(this); label-setText(Hello World); label-setGeometry(100, 80, 120, 30); // x, y, 宽, 高相对父窗口 }# QtDemo.pro —— 模块声明缺一个就链接不过 QT core gui greaterThan(QT_MAJOR_VERSION, 4): QT widgets QT sql network multimedia # 按手册章节需要逐行放开 TARGET QtDemo TEMPLATE app SOURCES main.cpp mainwindow.cpp HEADERS mainwindow.h RESOURCES res.qrc # 图标、图片资源第 2 章就要用三段代码对应三个职责main.cpp 管生命周期mainwindow.cpp 管外观.pro 管依赖。参数上要留意 setGeometry 的四个值前两个是相对父窗口的坐标后两个是宽高如果父窗口是顶层窗口那前两个就约等于屏幕坐标。resize 只改尺寸不改位置和手册第 2 章“控制窗体大小”里的 setMaximumSize/setMinimumSize 是两回事——前者是建议值后者是硬约束用户拖不动。.pro 里那行 greaterThan 是给 Qt4 兼容留的如果你确定只用 Qt5直接写 QT widgets 也行。但保留它没坏处某些旧构建环境会因此少报一个错。2.3 编译不过时先看这三处构建失败九成出在三个地方按这个顺序排比乱改代码快。第一是构建套件。工具里同时装了两三个 Qt 版本时很容易出现 qmake 指向 A 版本、编译器指向 B 版本的情况报错往往是找不到 QApplication 头文件或者“Qt version is not properly installed”。处理办法是打开构建和运行设置把套件里的 qmake 路径、编译器路径、调试器路径三行逐一核对然后删掉构建目录重新执行 qmake。血泪经验是别在原目录上反复点重新构建增量缓存会把错误藏起来。第二是 .pro 的模块声明。手册第 10 章数据库、第 11 章网络、第 7 章多媒体分别要 QT sql、network、multimedia。漏写的表现不是编译错误而是链接期报一堆 undefined reference或者在运行期发现 QSqlDatabase::drivers() 返回空列表。这种错最难查因为代码本身没问题。第三是源文件编码。老版本 MinGW 对不带 BOM 的 UTF-8 中文注释容忍度还行但一旦换到 MSVC 套件中文注释和字符串就可能报 C2001 或直接乱码。我的做法是所有 .cpp/.h 统一存成 UTF-8 with BOM字符串里出现中文就用 QString::fromUtf8 包一层省得后面来回折腾。3. 窗体与控件把第 2、3 章的范例复现成能跑的代码第 2 章和第 3 章是这份手册密度最高的部分窗体 8 个范例、控件 22 个范例基本上把日常 GUI 会碰到的东西铺全了。这两章不建议通读建议按“我要做的界面长什么样”倒着挑。下面挑四个使用频率最高的把参数和坑说透。3.1 窗体尺寸、位置、背景色三个函数定死外观手册里“控制窗体大小”“窗体初始位置及背景色”是两个独立条目实际项目里通常要一起写。// 固定 300x300并在屏幕 (100,100) 处显示背景红 this-setWindowTitle(Qt5 窗体应用); this-setMaximumSize(300, 300); // 上限 this-setMinimumSize(300, 300); // 下限和上限相等即锁定 this-move(100, 100); // 相对屏幕左上角 this-setStyleSheet(background:red;);setMaximumSize 和 setMinimumSize 同时设成一样窗口就彻底拖不动了这是最省事的锁尺寸写法。只设其中一个的话用户仍然能在另一个方向上拉伸很多“为什么还能拉大”的问题都出在这。move 的参数是相对屏幕的但如果这个窗口有父窗口move 就变成相对父窗口位置会整体偏移。判断方法很简单看构造函数的 parent 参数是不是 nullptr。setStyleSheet 这一行要小心它会把样式递归作用到所有子控件上。给主窗口设 background:red 之后里面的 QLabel、QPushButton 背景也可能被染红看起来像控件坏了。规范做法是只给需要背景的那个控件设或者在样式里加类名限定比如QMainWindow { background:red; }。这一点手册的范例没展开但实际用起来几乎必踩。3.2 无边框窗体拖动坐标记账和一个易漏的细节“移动无边框窗体”是第 2 章里信息量最大的一个范例它同时涉及窗口标志、鼠标事件、信号槽三块内容。// mainwindow.h 里声明 protected: void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; private: QPoint last; // 记录上一次的全局鼠标位置// 构造函数里去掉标题栏并补一个关闭按钮 this-setWindowFlags(Qt::FramelessWindowHint); QPushButton *btClose new QPushButton(this); btClose-setText(关闭); connect(btClose, QPushButton::clicked, this, QWidget::close);// 三个鼠标事件核心是全局坐标的差值 void MainWindow::mousePressEvent(QMouseEvent *e) { last e-globalPos(); // globalPos 是屏幕坐标不是窗口内坐标 } void MainWindow::mouseMoveEvent(QMouseEvent *e) { int dx e-globalX() - last.x(); // 鼠标这一帧移动了多少 int dy e-globalY() - last.y(); last e-globalPos(); // 先算差再更新顺序反了窗口会抖 move(x() dx, y() dy); // x()/y() 是窗口左上角的全局坐标 } void MainWindow::mouseReleaseEvent(QMouseEvent *e) { Q_UNUSED(e); // 释放时不需要再算一次移动已经处理完 }这段代码的关键在坐标体系。globalPos 拿的是鼠标在屏幕上的绝对位置x() 和 y() 拿的是窗口左上角在屏幕上的位置两者相减得到的 dx、dy 就是窗口该平移的量。手册原版在 mouseReleaseEvent 里又算了一遍 dx、dy 并 move 了一次功能上没错但会多一次无效移动窗口边缘偶尔会跳一下。我一般把释放事件留空只保留按下和移动两个。另一个隐蔽的坑如果这个无边框窗口是作为子窗口嵌在另一个窗口里的x() 和 y() 就变成相对父窗口的值此时 move 的基准错了窗口会越拖越偏。判断标准还是看 parent 是不是空。遇到拖不动的现象先确认 setWindowFlags 是不是在 show() 之前调的——放在 show() 之后调窗口会先闪一下再变无边框。还有一点Qt 5 里 e-globalPos() 返回 QPoint可以直接赋值到更高版本这套 API 被标记弃用改成 globalPosition().toPoint()。手册基于 Qt 5照抄没问题但如果你在同一套代码里混用不同版本的 Qt这里编译会报警告。3.3 资源文件与标题栏图标.qrc 的三段式路径“修改标题栏图标”这个范例难的不是 setWindowIcon是资源文件怎么建。手册给的路径是:/new/prefix1/ico这个字符串由三段拼起来冒号代表资源系统new/prefix1 是前缀ico 是别名。!-- res.qrc 的最终形态prefix 和 alias 都能自定义 -- RCC qresource prefix/icons file aliasappresource/app.ico/file /qresource /RCC// 前缀 /icons 别名 app拼成 :/icons/app this-setWindowIcon(QIcon(:/icons/app));参数说明prefix 是逻辑分组多个目录的资源可以共用同一个前缀alias 是省略路径的简写没有别名就得写完整相对路径形如:/icons/resource/app.ico。图标建议用 16x16 或 32x32 的 ICOPNG 也能加载但在部分系统的任务栏上显示会发虚。最常见的翻车是改完 qrc 或换了图片运行起来图标还是旧的。原因是 rcc 生成的结果没重新编译增量构建没识别到资源变化。解决方式是构建菜单里先执行一次 qmake再清理重编译。这个操作我后来养成习惯凡是动了 .qrc、.pro、图片一律先 qmake。3.4 控件与布局按参数表配 QGridLayout第 3 章 22 个控件范例逐个抄没意义真正要建立的是“控件 布局”的组合感。手册里 QHBoxLayout 和 QGridLayout 两节挨着放正好对照着看。QGridLayout *grid new QGridLayout; grid-addWidget(new QLabel(用户名), 0, 0); // 第 0 行第 0 列 grid-addWidget(new QLineEdit, 0, 1); grid-addWidget(new QLabel(密码), 1, 0); grid-addWidget(new QLineEdit, 1, 1); grid-addWidget(new QPushButton(登录), 2, 0, 1, 2); // 跨 1 行 2 列 grid-setColumnStretch(1, 1); // 第 1 列吃掉多余宽度 grid-setSpacing(8); // 控件间距addWidget 的五个参数依次是控件、行、列、跨行数、跨列数后两个省略时默认 1。setColumnStretch 是控制拉伸比例的关键不设的话窗口拉大时所有列等宽增长输入框会变得很怪。setSpacing 控制间距setContentsMargins 控制布局到父窗口的留白这两个经常被混用实际效果差挺多。有个使用习惯值得记布局不要一层套一层套太深。我有次做一个设置页套了四层 QVBoxLayout 里嵌 QHBoxLayout 再嵌 QGridLayout界面能显示但 resize 的时候卡顿明显。后来压平到两层问题就消失了。4. 文件、图形、数据第 5 到第 10 章怎么落地中段这几章是这份手册的分水岭前面的窗体和控件属于“看得见”从这里开始进入“用得着”。文件操作、图形图像、数据库这三块几乎每个实际项目都会碰到至少两块而它们的坑又都不在代码本身在选型和路径上。4.1 QFile、QSettings、QDomDocument三条不同的存储路径手册第 5 章把创建文件夹、写入文件、INI 读写、XML 读写放在一起看起来是并列关系实际上对应三种完全不同的场景选错会给自己埋雷。方式适用数据特点QFile QTextStream日志、导出文本、自定义格式完全自己管格式灵活但解析要手写QSettings配置项、窗口状态、用户偏好键值结构跨平台自动选存储位置QDomDocument层级数据、与外部系统交换结构清晰解析开销比前两者大写配置我基本只用 QSettings一行能省掉路径判断// 显式指定 IniFormat文件就会落在当前目录而不是系统注册表 QSettings cfg(config.ini, QSettings::IniFormat); cfg.setValue(db/host, 127.0.0.1); cfg.setValue(db/port, 3306); cfg.sync(); // 立即落盘别指望析构时一定写 QString host cfg.value(db/host, localhost).toString(); // 第二个参数是默认值 int port cfg.value(db/port, 0).toInt();参数上有个细节QSettings 不指定 IniFormat 时在 Windows 上默认写注册表很多“配置文件找不到”的困惑就来自这里。手册里 INI 那一节其实有提但容易看漏。另外 value() 的返回类型是 QVariant取的时候一定要带类型转换和默认值不带默认值遇到缺失键会返回空 QVariant转 int 得到 0转 QString 得到空串出错时毫无提示。XML 这块QDomDocument 的读取流程是打开文件、setContent、拿 documentElement、逐层 firstChildElement 往下走。节点遍历时要用 nextSiblingElement 而不是 nextSibling后者会把空白文本节点也当兄弟节点循环次数会翻倍。4.2 QPainter 图像特效调用顺序决定结果第 6 章从绘制文字线条一路排到模糊、着色、阴影、透明14 个范例。这一章的价值在于它把 QPainter 的变换系统和 QImage 的像素操作串起来了但手册按“效果”分节容易让人以为它们是并列的独立功能实际上很多效果要靠变换顺序堆出来。QImage canvas(200, 200, QImage::Format_ARGB32); canvas.fill(Qt::transparent); QPainter p(canvas); p.setRenderHint(QPainter::Antialiasing, true); // 抗锯齿画线画圆必开 p.setRenderHint(QPainter::SmoothPixmapTransform, true); // 缩放图片不失真 p.translate(100, 100); // 把原点挪到画布中心 p.rotate(30); // 顺时针 30 度y 轴向下所以正角是顺时针 p.scale(1.5, 1.5); // 先转后缩和先缩后转结果完全不同 p.drawPixmap(-50, -50, pix); p.end(); // 必须调用否则部分绘制不会提交顺序这件事值得单独说translate、rotate、scale 三个变换是有叠加顺序的代码里写的先后就是实际生效的先后。想让图片绕自己的中心旋转必须先 translate 到中心再 rotate如果先 rotate 再 translate转的是坐标系图片会绕着画布左上角甩出去。缩放还有一个坑QPainter::scale 放大后绘制线条的宽度也会跟着放大1 像素的边框会变成 1.5 像素看起来发虚。要固定线宽得用 QPen 的 setCosmetic(true)让画笔宽度不随变换缩放。手册里“模糊效果”“阴影效果”用的是 QGraphicsBlurEffect 和 QGraphicsDropShadowEffect这两个类只作用于 QWidget 和 QGraphicsItem不能直接怼到 QImage 上。想对图片做模糊常见做法是把 QImage 放进 QGraphicsScene 再渲染出来或者自己写一个简单的盒式模糊。这个边界手册没明说很多人照着写发现没效果就是卡在这。4.3 QSqlDatabase 与 SQLite先查驱动再连库第 10 章从查询驱动开始这个顺序是对的实际开发里也建议照这个顺序排查。// 第一步确认驱动列表里有没有 QSQLITE qDebug() QSqlDatabase::drivers(); QSqlDatabase db QSqlDatabase::addDatabase(QSQLITE, main); db.setDatabaseName(demo.db); // 相对路径落在工作目录 if (!db.open()) { qDebug() open failed: db.lastError().text(); return; } QSqlQuery q(db); q.exec(CREATE TABLE IF NOT EXISTS user( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER)); q.prepare(INSERT INTO user(name, age) VALUES(?, ?)); // 占位符防注入也省转义 q.addBindValue(A同学); q.addBindValue(20); q.exec();第一个参数是驱动名第二个是连接名。连接名看着多余但一个程序连两个库时它是唯一区分手段不写的话第二次 addDatabase 会覆盖第一次报“duplicate connection name”警告。路径是另一个高频坑。setDatabaseName 给相对路径时文件落在进程的当前工作目录而不是 exe 所在目录。在 IDE 里跑没问题双击 exe 就发现数据库“消失”了其实是创建到了别处。稳妥做法是用 QCoreApplication::applicationDirPath() 拼绝对路径。驱动列表为空说明 .pro 里没写 QT sql或者发布时 sql 插件没跟着走。这两件事现象一样原因完全不同用 drivers() 的输出就能区分。5. 避坑与排查复现这套范例时最容易翻车的五处这份手册的范例是能跑的但把它们搬进自己的工程失败率不低。下面五条是我在不同机器、不同项目里反复遇到的按“现象、原因、解决”记下来遇到了直接对号入座。5.1 构建期的两个高频问题第一条现象是编译时报一堆 undefined reference全是 QSqlDatabase、QTcpSocket、QMediaPlayer 这类符号代码本身没有任何报错。原因是 .pro 里漏了模块声明头文件能找到因为 Qt 的头文件搜索路径是全局的但链接期找不到对应的库。解决就一行按手册章节补 QT sql / network / multimedia补完必须重新执行 qmake光点构建不生效。第二条现象是改完图标、或者新加了一张图片程序跑起来还是旧图标甚至报“QPixmap: Cannot open file”。原因是 .qrc 的增量编译没触发或者文件路径里的相对位置和 qrc 所在目录对不上。qrc 里的 file 路径是相对 .qrc 文件本身的不是相对项目根目录这一点手册范例里用的是 resource/xxx.ico很容易被理解成相对工程。解决是先在构建菜单执行 qmake再清理重编译路径对不上就按 qrc 所在位置重新数一遍层级。5.2 运行期的两个行为异常第三条无边框窗口拖不动或者一拖就飞出屏幕。原因有三种可能setWindowFlags 调在了 show() 之后mouseMoveEvent 里先更新了 last 再算差值窗口有父对象x()/y() 是相对父窗口的值move 的基准错了。解决是逐项核对先看 flags 的调用位置再检查 last 的更新顺序最后看构造函数有没有传 parent。第四条给主窗口设了 setStyleSheet(“background:red”) 之后里面的按钮、标签背景全变了样。原因是样式表会往子控件继承QWidget 的 background 属性影响面尤其大。解决是把样式限定到具体类名写成QMainWindow { background:red; }或者干脆只给一个占满窗口的 QLabel 设背景主窗口本身不动。5.3 发布期的一个经典故障第五条现象是开发机上跑得好好的拷到另一台机器双击 exe要么没有任何反应要么弹出“could not find or load the Qt platform plugin windows”。原因是只拷了 exe没带 Qt 的运行时 DLL 和平台插件目录。解决是用 Qt 自带的部署工具在同目录跑一次# 在 exe 所在目录执行把所有依赖和插件收过来 windeployqt --release --no-translations app.exe执行完会多出 platforms、imageformats、sqldrivers 等目录。其中 platforms/qwindows.dll 缺了就是上面那个报错sqldrivers/qsqlite.dll 缺了就是数据库连不上但没有任何提示。参数说明--release 对应 release 构建--no-translations 去掉语言包能省几 MB需要多语言支持就别加。再往后做成安装包手册第 14 章给了两种思路一个是自解压式的打包一个是走安装包制作工具。我一般先用 windeployqt 把依赖收全再整体塞进安装包顺序反了会漏文件。6. 把目录当索引二次利用与验收方法这份 PDF 我用了几年最有价值的用法不是逐章读是把它当一张验收表。做法很简单每接手一个 Qt5 工程先按手册的十四章过一遍看这个项目用到了哪几块然后在目录旁边标注“已复现 / 待验证 / 不涉及”。标注完工程的边界就清楚了。下面这张表是我常用的对照表每一行对应手册的一章右边是验收动作和通过判据。它比读十页正文都管用因为每一步都能自己验证。手册章节验收动作通过判据第 2 章 窗体改标题、换图标、锁尺寸三处都生效且样式没污染子控件第 3 章 控件用一个表单页放 8 个以上控件拉伸窗口时布局不错位第 5 章 文件写一个 INI 再读回来键值类型一致缺失键走默认值第 6 章 图形图片旋转缩放后保存边缘不糊线宽不随缩放变化第 10 章 数据库建表、插一条、查出来drivers() 里有 QSQLITE第 14 章 打包拷到另一台机器运行无插件报错图标正常配合这张表我还会跑一段小脚本扫自己的范例目录确认每个章节的工程都还在、还能编。它不检查代码质量只检查“有没有丢东西”但这恰恰是最容易出问题的地方。# 扫描范例根目录按手册章节核对工程文件是否齐全 import os ROOT ./QtSamples REQUIRED [main.cpp, mainwindow.cpp, mainwindow.h] # 每个范例的最小集 for chapter in sorted(os.listdir(ROOT)): path os.path.join(ROOT, chapter) if not os.path.isdir(path): continue for name in sorted(os.listdir(path)): proj os.path.join(path, name) if not os.path.isdir(proj): continue missing [f for f in REQUIRED if not os.path.exists(os.path.join(proj, f))] # .pro 文件名不固定按后缀匹配更稳 has_pro any(f.endswith(.pro) for f in os.listdir(proj)) if missing or not has_pro: print(f[缺件] {chapter}/{name} - {missing or .pro})脚本干的事很朴素遍历章节目录检查每个范例工程是否带着最小文件集和 .pro。参数上 REQUIRED 可以按自己的模板改比如有的项目用 widget.cpp 而不是 mainwindow.cpp。跑一遍缺件的直接打印出来比一个个点开看快得多。这套方法里最值钱的一条经验是每复现一个范例先原样跑通再只改一个参数看结果怎么变。改尺寸就只改尺寸改颜色就只改颜色一次动一个变量。我曾经图省事一次性把窗口尺寸、背景色、图标全换了结果窗口显示异常排查了快两个小时最后发现是 setStyleSheet 把 QLabel 染红导致看起来像“窗口变小了”。从那以后我每次复现范例都强制走一遍“跑通—改一个参数—再跑通”的流程不跳步。希望这份拆解能帮你在拿到这份 PDF 时少走点弯路先跑通环境再按目录挑条目剩下的就是耐心了。本文还有配套的精品资源点击获取