讲真,VS2015 和 Qt 这对组合放到今天已经不算新潮,但真正靠它吃饭的人一点不少。很多工控上位机、老牌桌面工具、企业内部管理系统,底层都是这一套。把图形化 Hello World 在 VS2015 + Qt 里跑通,等于把这类项目从写代码到弹出窗口的完整链路都验证了一遍。这篇文章会把环境安装、项目创建、代码解析、编译排错全部走一遍,适合刚接手 Qt 项目的新人,也适合给老项目补文档的同学。
1. 先搞清楚:VS2015 和 Qt 到底各负责什么
很多第一次接触 Qt 的人会问,Qt 不是自带了一个 Qt Creator 吗?为什么还要费劲装在 VS2015 里?这俩不是重复了吗?其实没有重复。VS2015 是编译器、调试器和工程管理工具,它负责把你写的 C++ 代码变成 Windows 上能跑的 exe,还负责在断点处停下来让你看变量、查内存。Qt 是一套 C++ 类库,它提供 QMainWindow、QLabel、QPushButton 这些组件,让你不用从零开始调 Windows API 去画窗口。
用一句话说清楚:VS2015 解决“怎么写和怎么跑”,Qt 解决“界面和逻辑怎么搭”。两者结合以后,你既能在 VS 里写代码、调试、看调用栈,又能直接拖拽控件搭界面,这才是很多团队坚持用这套组合的根本原因。我见过不少新同学试图只装 Qt Creator,结果到了公司项目里,同事丢过来一个 .vcxproj 工程就傻眼了,因为 VS 的工程管理和 Qt 的工程管理终究是两套体系。
1.1 为什么不是 Qt Creator 而是 VS2015
Qt Creator 自己也能写 Qt 程序,而且它对跨平台项目非常友好,用 .pro 文件管理依赖也很简单。但它有一个缺点:很多 Windows 上硬核的调试场景,比如查看进程内存、调用 Windows API、用性能分析器,还是 VS 的地盘。Qt Creator 虽然内置了 GDB/CDB 支持,但和 VS 的原生调试器比起来,体验差距还是很明显。尤其是接手老项目的时候,代码里往往混合了第三方 C++ 库、C 代码、甚至少量汇编,VS 的符号解析能力在这个场景下会省很多时间。
还有一个现实问题:VS2015 对应的是 MSVC2015 编译器。Qt 官方发布的 Windows 二进制包,会对不同的编译器工具集做区分,比如 msvc2015、msvc2017、MinGW。你用 MinGW 版本的 Qt,用 VS2015 是没法直接链接的,因为 C++ 二进制接口不一样。反过来,你用 MSVC 版本的 Qt,配合 VS2015 的 MSVC 编译器,库和你的程序才能无缝匹配。这也是为什么我这篇一定要强调“版本匹配”,后面第 2 部分会专门展开。
1.2 哪些项目最适合这套组合
如果你是在做工业上位机、设备控制软件、数据采集界面,或者要对接某些厂商提供的 C++ SDK,VS2015 + Qt 是一个非常高概率出现的搭配。原因也很简单:这些项目的底层依赖库往往只提供了 MSVC 版本的编译产物,你不跟着用 MSVC 就会很难受。此外,Windows 平台运行的程序,MSVC 编译出的可执行文件对系统 DLL 的依赖更自然,和 Windows 生态的兼容性问题也更少。
当然,如果只是纯粹学习 Qt 语法,用 Qt Creator 可能更轻快。但要明白,学习环境和生产环境经常不是一回事。这篇教程用 VS2015 来做,就是因为很多项目组的真实开发环境就是这套。把 Hello World 做好以后,后续接入其他库、写单元测试、做性能调优,都能在同一个 IDE 里完成,不用频繁切换工具。
2. 环境准备:版本匹配与安装避坑指南
环境安装是最容易出问题的一环,而且问题往往不是“不会装”,而是“装错版本”。VS2015 和 Qt 之间一旦编译器工具集对不上,后续会出现各种莫名其妙的链接错误。我先说几个原则:第一,Qt 版本优先选 5.9 系列或 5.6 系列,这两个系列对 VS2015 的对应关系最清楚;第二,Qt 安装包一定要选带 msvc2015 字样的,不要选 MinGW 版本;第三,VS2015 尽量升级到 Update 3,后续用起来会省心不少。
我见过有人下载了 Qt 5.12 的 msvc2017 版本,硬要往 VS2015 里塞。编译的时候,Qt 的预编译库是用新版编译器生成的,VS2015 的链接器通常也能链接成功一部分,但只要遇到 C++ 标准库对象交互,就开始报一堆“无法解析的外部符号”。这种问题一旦出现,排查起来非常费劲,因为它不是语法错,而是二进制兼容错。
2.1 Qt 版本与 VS2015 匹配的铁律
Qt 官方在发布 Windows 安装包时,命名里会直接写出编译器信息。比如“qt-opensource-windows-x86-msvc2015-5.9.9.exe”,这个包对应的就是 VS2015 的 x86 版本。常见的还有“msvc2015_64”,对应 64 位 VS2015 程序。这里要注意,VS2015 本身是 32 位还是 64 位并不重要,重要的是你编译目标平台是 Win32 还是 x64。你要生成 64 位程序,就装 msvc2015_64 的 Qt 包;要生成 32 位程序,就装 msvc2015 的 Qt 包。理论上两者可以同时安装,默认路径会分别放在“msvc2015”和“msvc2015_64”两个目录下。
如果你的电脑系统是 64 位,我建议两个都装上。因为有时候项目最终要发布 32 位版本,或者某个第三方库只提供 32 位版本,到时候再回头补装会很耽误时间。安装 Qt 时组件不用全选,选一个你需要的编译器套件就够了,比如“MSVC 2015 32-bit”和“MSVC 2015 64-bit”下的内容。如果不确定以后会不会用到,把 32 位和 64 位都勾上也不会占太多空间,这个完全看个人习惯。
2.2 下载 Qt 安装包时怎么选组件
Qt 官方下载页面现在已经把版本列表收得比较深了,但旧版本仍然可以找到。进入下载页以后,选一个如 5.9.9 的版本,进入子目录,就能看到很多安装包。这时认准“qt-opensource-windows-x86-msvc2015”开头的文件。建议下载 exe 安装包,不要下载那个无法直接运行的文件。安装过程中,Qt 会让你选择安装路径,这里有一个必须遵守的规则:路径不要带中文,不要带空格,最好简单到类似C:\Qt\Qt5.9.9。很多莫名其妙的编译错误,最后查下来都出在安装路径上。
组件选择界面里,你会看到“Qt”这个大项下面有很多子项。对于 Hello World,不需要全选。只需要展开你选择的编译器套件,比如Qt 5.9.9 > MSVC 2015 64-bit,把这一项下面的内容勾上。如果你之后要用 Qt Creator,也可以顺便把Qt Creator装一下,但这不是必需。安装完成后,可以检查一下目录结构,确认C:\Qt\Qt5.9.9\5.9.9\msvc2015_64\bin里有qmake.exe。这个 exe 将来会被 VS 的 Qt 插件调用,是识别 Qt 版本的重要标志。
2.3 VS2015 与插件安装的三个检查点
VS2015 本身安装时,默认不会把所有 C++ 工具都装上。如果你安装时没有勾选“Visual C++”,后面打开 .vcxproj 会发现没有 C++ 编译选项。所以进入 VS2015 安装器,一定要确认“Visual C++”相关组件已经勾选。其次,建议把 VS2015 更新到 Update 3。原因很简单,更新补丁修复了大量 C++ 编译器问题,如果你用的是很早期的 VS2015 原始版本,编译器对 C++11 的支持会弱一些,还会影响 Qt 插件的稳定性。第三个检查点是 Windows SDK。如果电脑上安装了比较新的 Windows SDK,VS2015 也能用它;但如果你不确定,就保留 VS2015 自带的默认设置,不要手动切换 SDK 版本,避免出现“Windows SDK 版本冲突”的提示。
装好 VS2015 以后,还要安装一个关键插件:Qt VS Tools。在 VS2015 的菜单栏中找到“工具 > 扩展和更新”,然后在搜索框里搜“Qt”,一般能找到 Qt Visual Studio Tools 这个扩展。安装它需要联网,装完以后会提示重启 VS。重启后,菜单栏上会多出一个名为“Qt VS Tools”的菜单项,这就是我们接下来要用到的工具。如果你身处离线环境,也可以提前下载该扩展的 vsix 离线安装包,通过“扩展和更新 > 安装包”导入。操作上会绕一点,但思路是一样的。
3. 从零创建图形化 Hello World 项目
环境装好以后,就可以开始建工程了。很多人第一次在 VS2015 里找 Qt 项目模板时会蒙圈,因为没装插件之前,新建项目向导里根本不会出现 Qt 分类。确认插件加载成功以后,新建项目窗口里会多出“Qt”分类,里面包含“Qt GUI Application”“Qt Console Application”等模板。我们做图形化 Hello World,选“Qt GUI Application”而不是控制台项目。
创建过程比较简单,但有几个细节会直接影响后续编译。第一个是项目名称,建议叫 HelloWorld,不要前面加一堆汉语拼音或者用中文。第二个是项目保存路径,同样不要有中文和空格。第三个是解决方案名称,可以跟项目名保持一致。这三个点其实都是老生常谈,但确实能规避掉不少奇奇怪怪的路径编码问题。我遇到过最典型的一种情况:项目放在带中文的路径下,Qt 的 uic 工具对中文路径解析异常,导致界面头文件生成失败,报错信息还特别隐晦,不熟悉的人根本联想不到路径上去。
3.1 登记 Qt 版本,让 VS 知道去哪找库
创建项目之前,最好先确认 Qt 版本已经被 VS 正确认识。打开 VS2015 菜单栏中的“Qt VS Tools”,选择“Qt Options”,弹出窗口里会列出当前已登记的 Qt 版本。第一次安装插件时,这里一般是空的。点击“Add”按钮,然后在弹出的对话框里选择 Qt 安装目录下包含qmake.exe的那个路径。比如你装的是 64 位 Qt 5.9.9,那就选择C:\Qt\Qt5.9.9\5.9.9\msvc2015_64\bin,也就是 qmake.exe 所在目录,而不是上一级目录。
为什么插件要认 qmake.exe?因为 Qt 版本信息、模块路径、编译参数,最终都要靠 qmake 来告诉 VS。qmake 会根据 Qt 内部的 .pri/.prf 文件,把正确的头文件目录和库目录传给编译器和链接器。如果你登记路径的时候选错了,比如选到 Qt 安装根目录,VS 会报“No valid Qt version found”。另外,同一个电脑上装了多个 Qt 版本也不要慌,插件允许同时登记多套 Qt。你只要在项目属性里指定使用哪一套即可。新手最容易犯的错是,登记了多套版本之后,项目还默认使用第一次登记的那个,结果代码里引用了新版本模块,编译时却找不到头文件。
3.2 创建 Qt GUI Application 工程
现在开始新建项目。在 VS2015 菜单栏选择“文件 > 新建 > 项目”,左侧面板选择“Visual C++ > Qt”,中间会看到“Qt GUI Application”。选中后填好项目名称,点击确定。随后会弹出一个 Qt 项目向导,里面需要你选择基类(Base Class)。这里常见选项有 QMainWindow、QWidget、QDialog。对 Hello World 来说,选 QMainWindow 和 QWidget 都可以。区别在于 QMainWindow 自带菜单栏、状态栏、工具栏等主窗口框架,QWidget 是一个更纯净的空白窗口。如果你希望一上来就感受完整窗口结构,选 QMainWindow 更合适。
点击完成以后,VS 会生成一系列文件,并且自动打开一个.ui文件的编辑器视图。这个.ui文件实际上是一个 XML 格式的界面描述文件,你可以直接在上面拖控件。VS2015 安装 Qt VS Tools 后会集成界面设计器,双击项目里的.ui文件就能进入拖拽模式。很多老教程喜欢截图给大家看这个界面,但我更想强调:这个界面设计器底层是 Qt Designer 的嵌入版,如果你熟悉 Qt Creator 里的 Designer,操作逻辑几乎一样。左侧是控件面板,中间是窗口画布,右侧是属性表。从控件面板里把一个 QLabel 拖到画布中央,再双击它改成“Hello World”,这一步就完成了界面编辑。
3.3 工程里那些文件都是干什么的
新生成的工程里,文件数量不多,但每一个都有明确职责。HelloWorld.vcxproj是 VS 的工程文件,里面记录了编译选项、依赖项、平台配置。main.cpp是程序入口。MainWindow.h和MainWindow.cpp是主窗口类的声明和实现。MainWindow.ui是界面文件,保存了你在设计器里拖出来的控件布局。还有一个隐藏的ui_MainWindow.h,它不直接显示在工程里,而是在编译过程中由.ui文件自动生成,里面是界面控件的 C++ 类定义。
这个文件结构看起来简单,但理解它很重要。拿ui_MainWindow.h来说,它定义了Ui::MainWindow类,里面有我们拖进去的 QLabel 指针、setupUi方法。真正界面的构建过程是:程序运行时,MainWindow构造函数调用ui.setupUi(this),这个函数会创建 QLabel 等控件,并把它们布局到MainWindow上。这样就把界面设计和窗口逻辑分离了,之后界面有调整,不需要大改 C++ 代码。
3.4 编译前必须确认的三处设置
项目创建完成后先别急着按 F5,先检查三个地方。第一,右上角解决方案配置是不是 “Debug”,平台是不是 “x64” 或者“Win32”。你要和之前登记的 Qt 套件保持一致,比如登记的是 msvc2015_64,这里就应该选 x64。如果平台选错,编译时会因为找不到正确的 Qt 库而产生链接错误。第二,右键项目,进入“属性”,在“配置属性 > Qt Settings”中确认“Qt Installation”下拉框当前默认值是哪一个。如果机器装了多套 Qt,这一步检查就是为你省时间的。第三,确认“配置属性 > 常规 > 字符集”是“使用 Unicode 字符集”,英文环境下默认就是,但有些项目模板可能会改成多字节字符集,影响不大但不统一。
这几项都核对完毕,按 F7 编译。如果一切正常,输出窗口会显示“Build succeeded”。然后按 F5 启动调试,屏幕上应该会弹出一个空白窗口,里面显示 “Hello World”。如果你的窗口没弹出来,先别怀疑代码,八成是第三部分里提到的某一处设置没对齐。接下来我会把 Hello World 背后的代码逻辑拆开讲一遍,同时把编译运行时最常见的报错也整理出来。
4. Hello World 源码背后的运行机制
很多人跑通第一个 Qt 程序后,就急着做下一个功能,完全忽略这些自动生成的代码到底在干什么。等到后面出了问题,不知道应该改哪里。这一部分我用比较直白的方式,把 main.cpp、MainWindow、信号槽这三块核心机制讲清楚。哪怕你以后不用 VS2015 了,这套机制在 Qt 里也是通用的。
4.1 main.cpp:三行代码保住整个程序
打开main.cpp,你会看到类似这样的代码:
#include "MainWindow.h" #include <QtWidgets/QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }第一行创建了QApplication对象。别看它只是初始化了一下,Qt 程序的很多基础服务都是在这里启用的,比如全局资源、字体管理、窗口系统连接。第二行创建了MainWindow窗口对象,show()让窗口可见。第三行a.exec()进入了事件循环。
事件循环这个概念,我建议你从这里就重视起来。exec()本质是一个“无限循环”,但它不是空转,而是在等待鼠标点击、键盘输入、定时器超时这类事件发生。每来一个事件,Qt 就把事件交给对应的窗口对象去处理,处理完再继续等下一个。我们后面按下按钮改变文字的交互,就是靠这个循环才能响应的。这也是图形程序的执行模型和普通控制台程序最大的区别。
4.2 在 .ui 文件里拖出一个 Hello World
新建项目后,打开MainWindow.ui,左侧控件面板中找到“Display Widgets”分类,下面有一个 QLabel。把它拖到窗口中央,双击文字内容改成Hello World。如果你觉得文字位置不好看,可以直接用鼠标拖动,也可以通过右侧属性表里的geometry属性精确指定坐标。这里有一个细节:为了让文字水平居中,可以把 QLabel 的属性alignment设置为AlignCenter,这样字体长短变化时,控件内文本依然居中。
保存.ui文件后,回到 MainWindow.cpp,你会发现构造函数里有这样一句:
ui.setupUi(this);这一行的作用,相当于把你刚才在.ui文件里设计的所有控件,在代码层面“安装”到MainWindow这个窗口上。只要你不改这句,界面上拖了什么,运行时就会显示什么。这也是 Qt 开发效率高的原因之一,视觉部分和逻辑部分可以分开维护,设计师改界面,程序员改代码,两者通过setupUi衔接。
4.3 信号槽:让按钮一按就变字
Hello World 如果只是一个不能交互的窗口,显得有点单薄。我建议你在界面上再拖一个 QPushButton,文字改成“点击我”,然后在 MainWindow.h 里声明一个私有槽函数:
private slots: void onHelloButtonClicked();然后在 MainWindow.cpp 里实现:
void MainWindow::onHelloButtonClicked() { ui.label->setText("Hello Qt World"); }最后在构造函数中,加入:
connect(ui.pushButton, &QPushButton::clicked, this, &MainWindow::onHelloButtonClicked);按下按钮后,QLabel 的文字就会变成 “Hello Qt World”。这个流程的核心叫信号槽。按钮被点击时,会发出clicked信号,connect 函数把它和我们的槽函数连接起来。槽函数执行setText完成界面更新。在 Qt 里,所谓“信号”就是对象状态变化时的通知,“槽”就是对这种通知的响应函数。理解了这个机制,Qt 的编码思路就通了。
4.4 .ui 是怎么变成可编译的 C++ 代码的
你可能会好奇,.ui文件明明是 XML,编译器为什么能看懂?答案在于构建系统里有一个叫uic的工具。编译工程时,构建系统会调用 uic,把MainWindow.ui处理成ui_MainWindow.h,这个头文件在编译临时目录中生成,再被 MainWindow.cpp 通过#include "ui_MainWindow.h"引入。所以.ui文件每次改动保存后,下一次编译会自动重新生成对应的ui_MainWindow.h,不需要你手动参与。
这里有个新手常见误区:有人直接在ui_MainWindow.h里改代码,想加控件,结果一编译就被覆盖。正确做法是改.ui文件,或者直接在 C++ 代码里手动创建控件,而不是去改自动生成文件。如果你需要操作某个控件,也应该通过ui->控件对象名来访问,前提是该控件在.ui文件里已经设置了objectName。很多界面问题排查到最后,原因都是.ui里的控件名和代码里访问的名字不一致,这类错误编译时不会报,运行时才会报空指针,排查起来很浪费时间。
5. 编译运行与高频报错排查
Hello World 虽然简单,但编译运行阶段可能出现的错误并不简单。我按损坏程度排序,把最常遇到的几类问题整理成排查清单。你如果以后从网上下载旧项目来学习,遇到的报错大概率也是这几种,可以对照着快速定位。
5.1 链接错误八成是编译器工具集不对
错误表现:编译正常通过,但链接时出现“LNK2019:无法解析的外部符号”或者“LNK2038:检测到 mismatch 匹配项错误”。很多人的第一反应是代码问题,其实大部分情况是 Qt 库的编译器版本和 VS2015 不对应。比如你下载了 msvc2017 版本的 Qt,用 VS2015 去链接,就会出现 LNK2038,因为它检测到_MSC_VER版本不一致。
解决思路:回到第 2 部分,检查 Qt 安装是不是 msvc2015。如果确认是,再检查项目平台选的是 x64 还是 Win32,必须与 Qt 安装套件的位数一致。还要检查 Qt VS Tools 里登记和选择的版本是不是同一个。这三个点如果都对了,LNK 类错误基本可以排除。
5.2 头文件找不到时先查这四处
错误表现:编译时报fatal error C1083: 无法打开包括文件: "QtWidgets/QApplication"或类似信息。遇到这种问题,不要先去网上搜,先依次检查这四件事。第一,Qt VS Tools > Qt Options > Add“登记的路径是否正确;第二,当前项目的 Qt Settings 里Qt Installation有没有选中正确的版本;第三,项目属性里VC++ 目录 > 包含目录` 是否自动带上了 Qt 的 include 路径;第四,把 VS 重启一次,因为有时候插件加载的 Qt 环境变量没有实时刷新。
如果这四步都查了还是不行,可以手动在“项目属性 > 配置属性 > Qt Settings”里把 Qt Installation 重新选一次,点确定再重新选回来,这个操作会让 VS 重新生成一组 include 和 lib 路径,我实测过很多次都对症。如果你是从老同事手里拷贝的项目,还要注意.vcxproj里的 Qt 版本设置可能写死了某个绝对路径,环境不同会导致路径失效,这时也得手动改。
5.3 运行时缺 Qt5Cored.dll 的三种处理法
编译好了,一运行,弹窗提示“找不到 Qt5Cored.dll”。这个问题原理不复杂:程序启动时需要动态加载 Qt 的 DLL,但 Windows 找不到这个 DLL。解决方式有三种,按推荐程度排序。第一种,把 Qt 的 bin 目录添加到系统 PATH 环境变量。比如C:\Qt\Qt5.9.9\5.9.9\msvc2015_64\bin,添加后重启 VS,一般就能运行了。第二种,在 VS 项目属性的“调试 > 环境”里写一条PATH=$(QtDir)\bin;$(PATH)。这种方式只针对当前项目生效,不影响全局环境变量,多人协作时更安全。第三种,把要用到的 DLL 复制到 exe 所在目录,适合发布阶段。但开发阶段不建议,因为 DLL 一多,手动复制极易漏掉,调试时明明改了一处代码,运行起来却还是旧 DLL,容易产生假象。
我在实际项目里比较推荐第二种。它干净利落,不污染系统环境,也不影响同事的电脑。唯一注意点是$(QtDir)需要用 VS 能识别的宏,如果你的 Qt 路径没有登记到宏里,就写成绝对路径,但绝对路径可移植性差,建议还是先检查 Qt 宏是否可用。
5.4 用 VS 调试 Qt 代码的偷懒配置
VS 调试器对 QString、QList 这类 Qt 类型默认显示效果很差,看一个 QString 要展开一堆内部字段,效率很低。Qt VS Tools 插件实际上自带了一些数据类型可视化器,装好插件以后,默认会启用一部分。如果你发现某个 Qt 类型还是显示成一堆结构体,可以在工具 > 选项 > 调试 > 可视化工具里检查插件项是否被勾选。
这个能力在排查业务代码时非常有用。比如一个错误字符串传入函数以后,直接从调试器的“监视”窗口里就能预览 QString 的文本内容,不用再手动转换。尤其处理信号槽参数传递问题时,省下的时间不是一点半点。我建议在正式开发前先花十分钟熟悉这个功能,后面调试效率能提升不少。
6. 从 Demo 到实战:最容易被忽略的细节
跑通 Hello World,可以说你已经在 VS2015 + Qt 这条路上迈出最关键的一步了。但 Demo 和真实项目之间,还有很多容易被忽略的细节。下面这些内容,是我在跨过无数次坑以后总结下来的,希望你不用再走一遍。
6.1 项目命名和路径的教训
项目命名这件事,我在前面提了两次,这里再说一次,因为真的太重要。Qt 生成的界面头文件、moc 文件、编译缓存,都会引用项目路径。如果是中文路径,轻则编译缓存异常,重则 uic 或 moc 解析失败,报错信息又看不懂。命名也尽量以字母开头,不要带空格。你看很多成熟项目的名字,通常就是 HelloWorld、DeviceManager、DataAcquisition 这类,简洁干净。一旦项目进入中期想改名,牵扯的文件很多,成本非常高。
如果你是从示例代码复制项目,还要注意.vcxproj文件里声明的一些绝对路径,比如QtPlugins路径或QTDIR。复制项目到另一台电脑后,这些路径往往会失效。拿到一个老项目,第一步应该打开“Qt VS Tools > Qt Options”看版本登记,再打开项目属性看 Qt Settings 里选的是哪个版本,把错位的修正过来,再谈编译。
6.2 用 windeployqt 打包发布
开发阶段靠 PATH 跑起来没问题,但发布给别人的时候,你不能指望每台目标电脑都装 Qt,也不能手工把所有 DLL 一个个复制出来。Qt 在 bin 目录下自带一个windeployqt.exe,专门用来收集 Qt 程序必需的 DLL 和插件。使用方法是在命令行里进入 exe 所在目录,然后执行:
C:\Qt\Qt5.9.9\5.9.9\msvc2015_64\bin\windeployqt.exe HelloWorld.exe它会自动扫描这个 exe 依赖了哪些 Qt 模块,然后把对应 DLL 拷贝到 exe 目录,同时生成platforms、styles、iconengines等插件子目录。跑完以后,你可以直接把整个目录拷贝给没装 Qt 的机器运行。这个工具不挑项目,之后做正式项目发布也通用。要注意的是,Debug 和 Release 的 DLL 是有区别的,带 d 后缀的是 Debug 版本,发布时一定要用 Release 编译出的 exe 去执行 windeployqt,否则会把一堆 Debug DLL 带出去。
6.3 保留 .pro 文件,给自己留条跨平台后路
Qt VS Tools 在创建项目时通常会生成一个.pro文件,虽然 VS 下编译时几乎用不到它,但我建议不要删。这个.pro文件可以被 Qt Creator 直接打开,意味着同一个项目以后也能用 Qt Creator 在其他平台继续开发。很多团队会同时维护.vcxproj和.pro,虽然平时主要用 VS,但万一有人要在 macOS 上临时看一下界面代码,至少能打开工程。
如果你修改了 VS 工程,比如新增了一个模块,不要忘了同步到.pro文件的QT +=和SOURCES +=部分。这些工作看起来很琐碎,但在后续需要跨平台时能为你省大量时间。没有谁希望到了需要跨平台的那一天,才发现工程文件已经和源码对不上了。
6.4 版本库提交时记得忽略这些文件
如果你用 Git 管源码,一定不要把 VS 的编译中间文件提交进去。.vcxproj里有一个.filters文件可以提交,但.user文件是用户本地的配置,会记录你电脑上的路径,提交以后会给别人造成干扰。此外,Debug和Release目录、.qmake.stash、*.obj、*.pdb、.vs目录都不要提交。建议在项目根目录放一个.gitignore,把这几类内容全部排除。否则团队成员每次拉代码都会拉下来一堆和你本地路径相关的垃圾文件,轻则编译变慢,重则覆盖别人的本地配置。
如果项目里同时存在.pro文件,可以把Makefile、Makefile.Debug、Makefile.Release也加入忽略列表。这些文件是当年 qmake 在旧版环境生成的,换了环境以后反而会干扰新的构建。版本库只保留源文件和工程描述文件,这才是健壮的做法。
6.5 我的几个长期使用习惯
最后分享几个我在实际项目中沉淀下来的习惯。第一,每次新建 Qt 项目,第一件事不是写代码,而是把目录结构定好:src放源码,ui放界面文件,res放资源,doc放文档。Qt 项目小的时候无所谓,一旦大了,乱糟糟的目录会让所有人都头疼。第二,凡是用到的控件,都在.ui文件里设置一个有意义的objectName,比如btnStart、labelStatus,不要依赖默认的pushButton_2这种名字。自动生成的名字一旦界面调整就会变,代码里引用非常容易乱。第三,信号槽连接尽量使用新语法,就是connect(sender, &QObject::signal, receiver, &Object::slot)这种写法,编译期就能检查连接是否有效,比字符串签名更安全。第四,在main函数里尽量早一点处理高 DPI 适配,比如设置QApplication::setAttribute(Qt::AA_EnableHighDpiScaling),虽然 Hello World 用不上,但越早固化到项目模板里,将来越省事。
这四个习惯都是看起来不起眼、后期影响很大的事情。开发就像流水线,前期多花 10 分钟理顺,后期就能少花 5 个小时排查。你如果能把 Hello World 和这些好习惯一起执行起来,之后接手的任何 Qt 项目都会顺畅得多。