在第七章中,我们通过自动测试、异常矩阵和发布候选标准提高了项目稳定性。最后一章解决交付问题:构建 Release、收集运行依赖、验证干净环境、整理文档,并准备一条清晰的课程答辩叙事。
源代码能够在开发电脑上运行,不代表软件已经可以提交。真正的交付物应当在没有 Qt Creator、没有源代码、工作目录不同的环境中独立启动。
1. 本章目标
完成本章后,应当能够:
- 区分 Debug、Release 和部署目录;
- 为程序设置版本和发布属性;
- 使用 Qt 的 CMake 部署 API;
- 使用 windeployqt 检查 Windows 依赖;
- 验证平台插件和 SQLite 驱动;
- 在干净环境中测试最终程序;
- 整理 README、架构图、ER 图和测试报告;
- 设计 5~8 分钟答辩演示;
- 生成可复核的最终提交包。
2. 固定版本信息
项目版本应当有唯一来源:
project(course_manager VERSION 1.0.0 LANGUAGES CXX)
程序中可以读取:
QCoreApplication::setApplicationVersion(
QStringLiteral(PROJECT_VERSION));
为目标传入版本宏:
target_compile_definitions(course_manager PRIVATE
PROJECT_VERSION="${PROJECT_VERSION}"
)
关于页面、README、压缩包名称和答辩文档都使用同一个版本号,例如 CourseManager-1.0.0-windows-x64.zip。
3. Release 构建
使用独立构建目录,避免 Debug 与 Release 产物混合:
cmake -S . -B build-release
cmake --build build-release --config Release
构建前确认:
- 选择的 Qt Kit 与开发时一致;
- CMake 配置成功;
- 没有未处理的编译警告;
- 测试在 Release 配置下也能运行;
- 程序版本号正确;
- 没有依赖本地绝对路径的资源。
不要把 Debug DLL 与 Release 程序混合,也不要把整个构建目录直接作为最终提交包。
4. 使用 CMake 部署 API
Qt 6 可以通过 CMake 生成部署脚本。先加入安装规则:
include(GNUInstallDirs)
install(TARGETS course_manager
BUNDLE DESTINATION .
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
qt_generate_deploy_app_script(
TARGET course_manager
OUTPUT_SCRIPT deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${deploy_script})
构建后安装到独立目录:
cmake --install build-release `
--config Release `
--prefix package
部署脚本会调用平台对应工具收集 Qt 运行依赖。最终 package 应是一个自包含的安装目录,而不是源码目录的复制品。
qt_generate_deploy_app_script() 适用于 Qt 6.3 及更高版本。如果课程环境固定在更早版本,需要改用对应版本支持的部署方式。
5. 使用 windeployqt 手工检查
在 Qt 对应 Kit 的命令行环境中,也可以对 Release 可执行文件运行:
windeployqt --release --dir package CourseManager.exe
实际可执行文件路径根据生成器和构建目录而定。运行前先定位正确的 Release 程序,不要对 Debug 版本打包。
windeployqt 会收集 Qt DLL、平台插件、图像格式插件和编译器运行库等依赖,但项目自己的第三方库和外部资源仍需要自行检查。
6. 检查最终目录
一个简化的 Windows 包可能包含:
CourseManager-1.0.0/
├── bin/
│ ├── course_manager.exe
│ ├── Qt6Core.dll
│ ├── Qt6Gui.dll
│ ├── Qt6Widgets.dll
│ ├── Qt6Sql.dll
│ ├── platforms/
│ │ └── qwindows.dll
│ ├── sqldrivers/
│ │ └── qsqlite.dll
│ └── styles/
├── README.md
├── 使用说明.pdf
└── LICENSES/
项目使用 SQLite 时,要特别检查 sqldrivers/qsqlite.dll;Widgets 程序启动需要 platforms/qwindows.dll。只有把 DLL 放在正确的插件子目录中,Qt 才能发现它们。
不要把自己的真实课程数据库、个人姓名、令牌或调试日志打进提交包。演示数据使用专门准备的匿名样例。
7. 数据库首次启动策略
程序首次启动时:
- 使用 QStandardPaths 获取用户数据目录;
- 创建目录;
- 创建空数据库;
- 执行表结构和版本迁移;
- 可选地询问是否导入演示数据;
- 显示正常空状态。
不要默认在程序安装目录写数据库。该目录可能只读,也可能在更新或解压新版本时被覆盖。
如果要附带演示数据,可以把 JSON 模板放进 .qrc,首次启动时由用户主动选择导入,而不是把开发数据库复制到安装目录。
8. 干净环境部署测试
理想情况下,在没有安装 Qt 的另一台 Windows 电脑或虚拟机测试。至少执行:
- 解压到一个全新目录;
- 直接双击可执行文件;
- 确认没有 Qt Creator 或构建目录依赖;
- 测试首次数据库初始化;
- 完成新增、搜索、修改、删除;
- 测试中文路径和包含空格的路径;
- 关闭并重启;
- 测试导入导出;
- 断网后测试本地核心功能;
- 删除用户配置后再次首次启动。
不能只在源码目录旁运行,因为程序可能无意中读取了构建目录中的插件或资源。
9. 部署问题定位
提示找不到 Qt6Widgets.dll
运行依赖没有部署,或者程序与 DLL 的体系结构、编译器不一致。使用同一 Qt Kit 的 windeployqt 重新生成目录。
提示无法初始化平台插件
检查 platforms/qwindows.dll 的目录层级。不要把它直接放在 exe 同级后就删除 platforms 目录。
开发环境能查数据库,打包后提示驱动未加载
检查 sqldrivers/qsqlite.dll,并输出 QSqlDatabase::drivers() 进行诊断。
图标、样式或模板丢失
应打包的静态资源优先放入 .qrc。确实需要外部文件时,使用应用目录或标准数据路径构造位置,并在安装规则中显式复制。
程序启动后无法创建数据库
检查是否错误地把数据库写到安装目录。改用 QStandardPaths::AppDataLocation,并显示实际错误原因。
10. 最终文档清单
README
至少包含:
- 项目简介;
- 主要功能;
- 技术栈;
- 开发环境;
- 源码构建步骤;
- 程序运行方式;
- 数据文件位置;
- 已知限制;
- 项目结构。
使用说明
面向普通用户说明:
- 首次启动;
- 创建课程和作业;
- 搜索、修改、删除;
- 导入导出;
- 数据备份;
- 常见错误处理。
设计与测试材料
准备:
- 需求与功能范围;
- 模块架构图;
- 数据库 ER 图;
- 关键类关系;
- 测试用例表;
- 测试结果;
- 关键界面截图;
- 已知问题和后续计划。
文档中的截图、功能和版本必须与最终提交程序一致。
11. 最终提交包结构
建议分开交付源代码、运行程序和文档:
QtCourseProject-1.0.0/
├── source/
│ ├── CMakeLists.txt
│ ├── src/
│ ├── resources/
│ ├── tests/
│ └── README.md
├── application/
│ ├── bin/
│ ├── README.md
│ └── 使用说明.pdf
├── documents/
│ ├── 需求分析.pdf
│ ├── 设计说明.pdf
│ ├── 测试报告.pdf
│ └── 答辩演示.pdf
└── checksums.txt
压缩前从该结构直接运行一次程序,并确认没有临时构建文件、个人数据库、绝对路径和大体积无关素材。
可以生成校验值:
Get-FileHash .\CourseManager-1.0.0-windows-x64.zip `
-Algorithm SHA256
校验值便于确认上传和下载后的文件没有损坏。
12. 设计 5~8 分钟答辩
推荐节奏:
| 时间 | 内容 |
|---|---|
| 0:00~0:40 | 问题背景和项目目标 |
| 0:40~1:20 | 功能范围与技术选型 |
| 1:20~4:30 | 按固定脚本演示核心流程 |
| 4:30~5:30 | 架构、Model/View 与数据库设计 |
| 5:30~6:20 | 特色功能和关键技术难点 |
| 6:20~7:10 | 测试、异常处理和部署验证 |
| 7:10~8:00 | 总结、限制和后续方向 |
答辩应围绕“问题—设计—实现—证据”展开,而不是逐个朗读类名。
13. 演示准备
演示前准备:
- 一份干净数据库;
- 一份包含少量匿名数据的演示数据库;
- 一份可成功导入的 JSON;
- 一份故意损坏的 JSON;
- 固定的课程和作业名称;
- 离线可用的程序包;
- 关键界面截图或短视频作为备用;
- 源代码关键位置书签。
现场演示顺序与第六章中的脚本保持一致。不要临时输入过长内容,也不要依赖不稳定的外部网络完成核心演示。
14. 常见答辩问题
为什么选择 Qt Widgets 而不是 QML
项目以传统桌面管理界面、表格和表单为主,Qt Widgets 组件成熟,Model/View 支持完整,并与 C++ 业务代码直接配合。
为什么使用 SQLite
项目是单机课程软件,数据量和并发要求有限。SQLite 无需单独部署服务器,支持事务和结构化查询,适合独立桌面应用。
为什么不用 QTableWidget
数据需要被查询、排序、过滤、持久化和测试。Model/View 能把数据与显示分离,并通过代理模型复用排序和过滤能力。
如何保证数据库一致性
输入先经过业务校验,查询使用绑定参数,多步导入使用事务,失败时回滚,并通过集成测试验证关键约束。
多线程解决了什么问题
只有真实耗时任务才移到 worker,GUI 始终留在主线程。普通网络请求使用 Qt 的异步 API,不额外创建线程。
15. 七个练习步骤
| 顺序 | 学习与实践 |
|---|---|
| 第 1 步 | 固定 1.0.0 版本号并构建 Release |
| 第 2 步 | 添加 CMake 安装与部署脚本 |
| 第 3 步 | 使用 windeployqt 检查 Qt 依赖 |
| 第 4 步 | 在干净目录或另一台电脑测试 |
| 第 5 步 | 整理 README、使用说明和设计文档 |
| 第 6 步 | 按 5~8 分钟结构完成一次模拟答辩 |
| 第 7 步 | 生成最终压缩包、校验值和备份 |
16. 最终验收清单
- Release 构建和全部测试通过;
- 程序版本号在各处一致;
- 部署目录不依赖 Qt Creator;
platforms/qwindows.dll存在且位置正确;sqldrivers/qsqlite.dll存在且可加载;- 首次启动可以创建用户数据库;
- 中文路径和含空格路径测试通过;
- 程序重启后数据和设置正确;
- 提交包没有个人数据库和敏感日志;
- README、使用说明、架构图和测试报告完整;
- 演示数据、损坏样例和备用截图已经准备;
- 5~8 分钟答辩可以在规定时间内完成;
- 最终压缩包能够重新解压并独立运行;
- 已保存最终压缩包的 SHA-256 校验值。
至此,这条 Qt 课程项目路线完成了从开发环境、界面原型、事件与 Model/View、SQLite 数据闭环,到特色功能、MVP、测试和部署的完整过程。真正值得保留的不只是最终软件,还有一套可以迁移到下一次桌面项目中的开发方法。
官方参考:使用 CMake 部署 Qt 应用 | Windows 部署 | qt_generate_deploy_app_script
上一篇:第 7 章:测试、异常处理与发布候选 | 返回:8 个章节的项目驱动学习路线