用 Qt Creator 做个简单软件
用 Qt 做一个简单的软件
早年用 Pyinstaller 做 Python 的软件,感觉软件体量太大了,不够轻量级,动不动就上百 M。后来研究了一下,发现问题根源在于软件嵌入了环境里的各种大的包和库,例如 numpy 或 matplotlib,再加上自身的 PyQt,有多大可想而知。
后来为了轻量化 exe,了解到还有
- cpp + Qt
- Rust + egui
- go + fyne
2 和 3 是新起之秀,好写,启动也快,界面还行,但数值/绘图库生态没 cpp 那么工业化,在学术科研上没啥优势,所以最后还是打算走传统主流的 cpp + Qt 算了。
此外 1 和 2/3 还有一个区别,Go/Fyne、Rust/egui 经常能一个 exe 拿走就跑,而 Qt 默认往往要 exe + 一堆 dll + plugins。这差异主要来自两点:静态链接的默认程度和插件/平台抽象的架构。
所谓的静态库(.lib/.a),就是在编译阶段,编译器会把库里所有用到的代码“复印”一份,直接塞进你的 .exe 文件里。缺点是体积大,更新麻烦。动态库(.dll/.so),编译时,.exe 里只记下了需要用到某个库的名字。程序运行的时候,它会去电脑文件夹里临时找这个 .dll 文件。缺点是依赖性强,只把 .exe 带走会报错。
Qt Creator 下载地址:https://www.qt.io/zh-cn/development/download
Qt 软件 GUI 的全局逻辑
必须先对整个软件制作的大局观有所了解,再细究每个环节的具体行为,我们才能对软件制作流程有更清晰的认识。
-
在 Qt Creator 里创建一个项目后,会得到一个文件目录
1
2
3
4.qtcreator/
build/
CMakeLists.txt
main.cpp其中
.qtcreator/是 Qt Creator IDE 的私有配置,是编辑器自己的配置目录,类似 VSCode 的.vscode/,不用管build/是编译输出的目录,是 CMake 构建的目录。里面会有编译产生的中间文件、自动生成的文件、最终exe、缓存等。该目录是生成物,可以随时删除重新生成。CMakeLists.txt是整个项目的构建规则,相当于是软件的构建说明书。它高速 CMake 这个项目叫什么,用什么 cpp 标准,依赖哪些 Qt 模块,哪些源文件要编译,要生成什么类型的 target(.exe)。因此,可以将 Qt Creator 理解为 CMake 的前端。main.cpp是 cpp 程序的入口,它做了三件事:- 创建 Qt 应用对象(QApplication)
- 创建窗口(交互界面)
- 启动事件循环
-
先了解 CMake 和 CMakeList 的关系和行为
众所周知,光有程序代码,就算跑起来也不能算我们平时生活中认知的软件,顶多只能算脚本。普通人认为的软件,是一个可执行文件,点击即用,而跑程序代码相对于点击即用的软件,多了一道叫做编译的工序。所谓的编译就是将人类用高级语言例如 C,Python,Matlab 写的脚本翻译成计算机能读懂并执行的二进制可执行文件,CMake 就是干这件事的,但它不是编译器(MSVC / GCC / Clang)而是构建系统生成器(build system generator)。
1
2
3
4CMake → 生成 Makefile/Ninja
Make/Ninja → 调用 编译器
编译器 → 生成 .obj/.o
链接器 → 生成 .exe就和人类翻译员一样,你需要根据不同场合不同对象来确定要翻译到什么程度,这样才能让计算机正确执行我们想要的功能。因此,Qt 就是通过 CMakeLists 去配置 CMake 的各种参数,包括:
- 定义工程/全局规则:最低版本、项目名、Cpp 标准、编译选项等
- 找到依赖:Qt6(以及 Widgets / Core / Gui …)
- 生成目标(target)并把东西挂到 target 上
-
了解 main.cpp 干了什么
main.cpp 作为 GUI 的核心,做了三件事
- 创建了 QApplication(整个 GUI 系统的核心)
- 创建主窗口对象
- 启动事件循环
a.exec()
当你在软件界面上点击按钮时:
- 操作系统产生一个“鼠标点击事件”
- 这个事件被送进 Qt 的事件队列
- Qt 的事件循环(a.exec())取出事件
- Qt 找到对应按钮对象
- 触发按钮的 signal(信号)
- 调用连接的 slot(槽函数)
由此实现了普通人认知上的软件功能
Qt 软件的调试与运行
这里先直接拿一个现成的案例跑,走走软件制作流程,这里就用示例里的计算器应用(Calqlatr)
点击左侧编辑栏,可以看到当前项目列表。calqlatr 是项目文件夹,包含了资源文件夹和源代码文件夹。GUI 设计代码就在源代码文件夹里改。
点击左侧调试栏,我们发现底侧输出栏和上方代码栏之间多了一个调试器,点击 Start Debugging… 就能调试并运行该计算器软件
测试了没问题,打开左侧项目栏,可以看到构建设置。所谓的构建设置,就是前面提到的 CMake 如何构建不同场景下的软件包
所谓的场景,指的是 CMake 的不同构建模式。它决定了:
- 是否开启调试信息
- 是否开启优化
- 生成的程序体积
- 是否适合调试
- 运行速度如何
我们先不管每个模式具体有啥不同,直接添加 Release 发行版并在左下角启用
最后点击左下角的小锤子,构建软件包
点击左上方视图栏窗格,打开 build 的文件夹
我们可以看到,此时 build 文件夹内有俩构建好的软件包,分别对应 Debug 和 Release 模式
Qt 软件的部署与打包
这里要明晰一个容易被混淆的概念,部署(Deploy)和分发(Distribute)
Deploy(部署)
把程序连同依赖环境一起“布置”到某个运行环境,使其可以正常运行。
关键词是:
- 解决运行依赖
- 放到目标机器
- 让它能跑起来
Distribute(分发)
把已经可运行的软件交付给用户(发布给别人)。
关键词是:
- 打包
- 发布
- 给用户下载/安装
我们现在想要干的事情同时包含部署和分发,因为你光在本地构建运行好了软件没用,你要让别人能够跑起来那才算成功!
Qt Creator 部署的流程如下:
1 | Qt Creator 构建 Release |
这个步骤本质是:
在 Windows 上为你的程序做“部署准备”(deployment preparation)
因为 windeployqt 的作用是:
- 扫描 exe
- 找出 Qt 依赖
- 拷贝 DLL
- 拷贝 plugins
- 拷贝 platforms/qwindows.dll
- 拷贝 translations
- 必要时拷贝 QML 模块
接下来详细介绍操作流程
-
首先在心仪的地方创建一个空文件夹。这里我直接在 build 目录下创建了一个 dist 文件夹,并在该位置打开 cmd
-
此时我们要使用 windeployqt 这个命令。但使用该命令前,我们需要将该命令的路径添加至环境变量,并将 Release 中的 exe 文件复制粘贴进 dist 文件夹
-
在 cmd 中输入
windeployqt --qmldir E:\Qt\Examples\Qt-6.10.2\demos\calqlatr\build\Desktop_Qt_6_10_2_MinGW_64_bit-Release\qml calqlatr.exe并回车这里我贴出了 qml(Qt Meta-Object Language) 的完整路径,qml 是一种基于声明式语法的脚本语言,主要用于构建流畅、现代化、高动态的用户界面(UI),是 Qt Quick 技术的核心。如果没有 qml 就不写。
运行完毕后我们发现 dist 文件夹中已经塞满了文件,双击 calqlatr.exe 后发现程序正常运行,部署成功。
现在的 dist 文件夹已经是一个完整的软件包了,你可以将整个文件夹拷走。只要文件夹内的文件完整,操作系统匹配,软件在哪儿都能运行,至此我们完成了本地部署测试。
-
现在要准备分发工作了,所谓的分发,就是将整个软件包打包成一个单独的安装包,以供发布给用户下载安装。这里我们使用 Inno Setup Compiler 来演示软件的打包。
首先新建一个脚本,跟着 Wizard 走
找到软件执行 exe 文件,并将整个 dist 文件夹都选上
后面直接一路 next(如果有想变更的设置可以自己改),最后 finish 了直接 compile
最后得到一个单独的安装包
最后打包好的安装包,就是大家平时日常生活中使用的软件安装包了。大家只需要双击并按指引进行程序安装,就能在桌面上看到软件的快捷方式,双击就能使用该软件。
忘了说明,输出的安装包在 Build -> Open Output Folder 里






