先说明一下,本水文老周仅讨论新版的 Qt 6,旧版的 Qt 不讨论。
尽管 Qt 有自己的开发环境,但老周必须说句不装逼的话:真的不好用。说起写代码,当然了,用记事本也能写。但是,有个高逼格的工具,写起来不仅效率高,而且舒服。
Qt 应用程序本质上就是 C++ 开发的代码,所以,不用官方工具是没有问题的。老周第一个想到的,不用猜,必是 VS。在 Windows 上,用 VS 也是没问题的。
安装的时候,工作负载可以选“使用C++的桌面开发”,这个其实不选也可以的,老周已做过实验,不选这个也能编译。所以,可以在单个组件中安装以下各项:
1、C++核心功能;
2、C++ 2022 可再发行程序更新包;
3、MSBuild(这个装上好一点,不装也没报错);
4、MSVC 143 C++ 生成工具(这个是重点,要装,要装);
5、用于 Windows 的 CMake 工具(这个也必须装上);
6、Windows SDK 任选一个版本,建议越新越好(自己编译源代码时必须)。
7、其他的组件自己看心情。
如果你不用 VS,但在 Windows 上也要装 MSVC 生成工具。在 Windows 上还是建议用微软的编译器,不容易出现莫名其妙的错误。老周实验过,用 Windows 版的 g++ 编译失败。
当然本文讲的 VS Code,但如果是 Windows 平台,也要装 VS 生成工具的。
-----------------------------------------------------------------------------------------------------------------------
编译源代码
Qt 现在也开始装X了,编译好的内裤只支持在线安装,十有八九慢到你要装几天才能装好,而且体积比 VS 还要大几倍。想离线安装只能下载源代码自己编译。
编译源代码需要以下工具:
1、Windows SDK,否则会找不到相关 .lib 文件而出错。
2、Python,3.x 后随便找个版本。可以下载嵌入版,不用安装,解压后,把Python可执行文件所在的目录路径添加到 PATH 变量中。
3、Perl。可以下载绿色版压缩包,解压到某目录,将包含 perl.exe 的目录添加到 PATH 环境变量中,一般位于 <解压后目录>Perlperlbin。
下载源码可以用国内镜像,如清华大学的:Index of /qt/archive/qt/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
最新的是 6.3,进去之后,不要下载整个源码包,而是找到 submodules 目录。核心组件是 qtbase-everywhere-6.xxx。
qtbase 是基础包,只编译这个模块的代码也能写 Qt 程序。解压之后,放在一个路径无空格无特殊符号的目录下,如 E:SDKQt。然后执行一下 configure 脚本,Windows 上是有后缀 .bat 的,Linux 脚本无后缀。
命令行参数可参考帮助文档,实际上我们只关心一个参数 -prefix。这个参数指定在编译成功后,复制(安装)动态库的目录。因为编译时会产生许多后期没用的文件,所以才要指定这个路径。操作方法:
打开 “Visual Studio 2022” -- "x64 Native Tools Command Prompt for VS 2022"。
不要用 Developer Command Prompt for VS 2022,因为用这个你要指定 CPU 架构,若不指定默认编译出来的库是 32 位的。
【注意:下面输入命令这一大段,你先别着急跟着输入。请你先看完了再输入。因为这 Qt 6 在编译前的配置有些雷区。即在“+++++++++++”与“+++++++++++”之间这一大段内容】
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
先看最保险的操作,全按官方文档的来,基本保持默认。
打开 x64 Native Tools Command Prompt for VS 2022 工具的命令提示窗口,输入:
cd <源码路径>
configure -prefix F:Qt6Libs
这样配置之后,将来在执行安装时会把生成的 .dll 复制到这个目录下。这厮好像重复执行会报错。老周一般是懒得去找错误,有时候就算找到错误在哪个 cmake 文件也解决不了问题,最直接有效的方法是全删掉,再从下载的压缩包里重新解压。官方文档说删除 CMakeCache.txt 文件可以,但老周尝试过,也是会报错的。
一切顺利之后,直接交给 CMake 解决。编译:
cmake --build .
. 是源码所在目录,因为上面我们已经 cd 到源码目录了,所以这里用个“.”表示当前目录。
运气好的话,一次通过。这时候电脑的 CPU 风扇会发疯,请做好心理准备。因为只编译一个基础模块,所以花的时间会少一些。
编译成功后,还要执行一下安装操作:
cmake --install .
后面的“.”依然指的是当前目录(源码目录),编译后的二进制文件(重点是那些 .dll)会复制到你刚才用 -prefix 参数配置的路径下。如刚才配置的是 F:Qt6Libs。
上面的方案是保证出错概率最低的做法,但是,生成文件会和源码混在一起,想手动清理它们估计会累死人。如果想三个基本目录相互隔离,就要用接下来的方法。这三个目录是:
1、源码。
2、build 输出目录。
3、安装目录。
我们来假设一下:
1、源代码:G:KitsQt6srcqtbase
2、build 输出目录:G:KitsQt6build
3、安装目录:G:KitsQt6installed
其实,这些目录都在 G:KitsQt6 下面。
废话一下,我现在的想法是:保留源代码目录不变,想留着将来重复用;把生成/编译输出的东东放在 build 目录,编译好后的二进制文件安装到 installed 目录。下面开始操作。
【警告:以下操作出现灵异事件的概率大,请鼓起勇气尝试。世事难料,各自珍重】
首先,打开 x64 Native Tools Command Prompt fo VS 20XX,定位到 G:KitsQt6build,这个路径要根据你实际的路径写。
cd /d G:kitsQt6build
命令工具窗口当前目录一般是 C 盘,要跨分区 CD 的话,要加上 /d 参数。
保持 build 目录为当前目录不要改变,在 build 目录中执行 configure 脚本。
..srcqtbaseconfigure -prefix ..installed
老周这里用的是相对路径,你也可以用绝对路径。注意 -prefix 参数是一个短横线的,不能写成 --prefix,会出错。如果看到下面这一行,说明你运气好,第一关算是过了,接下来的编译成功率很高。
Build files have been written to: G:/Kits/Qt6/build
接下来的操作就和前面的一样了。保持当前目录在 build 不变,依次执行:
cmake --build . cmake --install .
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
大约会编译 1700 多个目标。这过程中很有可能会出错退出。可以尝试重新执行 cmake --build . ,一般会成功的。 在 installedbin 目录下你会看到许多 .dll,这说明一切顺利。
编译默认是生成动态库的,所以在 configure 时我们不用改。建议用动态库,若编译为静态库,做项目时会涉及授权问题,也就是说你要购买。
配置 VS Code
编译完毕后,就是配置 VS Code 了,其实就是安装插件罢了。这几个插件少不了:
1、C/C++(微软官方的)
2、CMake Tools(也是微软官方的)
3、CMake Language Support(有了这个,写CMake时有智能提示)
有以上这几个就够玩了。另外,微软有个集合包,叫做 C/C++ Extension Pack,会一次安装一堆 C++ 有关的插件。觉得有必要可以装装,觉得没必要就当它透明。
打开 VS Code 的设置页,找到扩展中的 CMake Tools,滚动到 Environment,点“添加项”设置一个环境变量。
PATH = G:KitsQt6installed;G:KitsQt6installedbin;%PATH%
【键】是“PATH”,【值】是 = 后面那串。路径就是你刚才 Qt6 安装的目录,包括安装目录,以及安装目录下的 bin。
保存退出,收工。
开始装逼
如果上面各步骤都成功,我们现在可以开写玩了。
在 VS Code 中打开一个目录作为工作区。然后按 【ctl + shift + P】,输入“cmake”,找到“CMake 配置”命令,执行。
编译器选择 amd64 的,如果你要 32 位的就选 x86。
【注】如果你要写 32 位的,那前面在编译源代码时也要编译一份 32 位的动态库。这个你懂的,32 位和 64 位的二进制文件是不同混用的。
这时,提示还没创建 CMakeLists.txt ,那就点创建呗。但是,生成的 CMakeLists.txt 文件中的东东很多不是我们所需要的。凡是有 enable_testing,CTest 什么的,全部干掉。
大致内容如下:
cmake_minimum_required(VERSION 3.15.0) # 项目名称 project(testApp LANGUAGES CXX) # 设置变量 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) # 引用需要的库 find_package(Qt6 REQUIRED COMPONENTS Core Widgets Gui) # 添加源代码文件 add_executable(testApp WIN32 main.cpp) # 与相关的库链接 target_link_libraries(testApp PRIVATE Qt6::Widgets Qt6::Core Qt6::Gui)
1
3:设置变量。
CMAKE_CXX_STANDARD = 17 C++版本号 ,不要低于17。
CMAKE_CXX_STANDARD_REQUIRED = on 或 yes 或 1,和上面一起,必须符合C++版本。
CMAKE_AUTOMOC = on 或 yes 或 1,这个在Qt 项目里一般要开启,允许一些独特语法转译为C++代码。说白了就是 Qt 里面的信号和槽,用到特定的语法(其实这些语法是用宏定义的)。
CMAKE_AUTOUIC = on 或 yes 或 1,这个如果用到了 uic 资源时才会开启,没用到就可以不写。
4:引入要使用的库,Qt6 中使用 find_package 命令,格式都是固定,官方文档中有,可以照着抄。
5:添加源代码文件。
第一个是目标名,一般和项目名称相同,你可以自己取名。接着 WIN32 不能少(仅限于 Windows),否则窗口出不来,只出来控制台。main.cpp是代码文件,有多个代码文件也要写上,比如 a.cpp b.cpp c.cpp,如果写漏了就导致有的文件没有被编译,那你的程序能运行起来才怪呢。
6:链接。把目标(上面 add_executable 就是为目标加了源文件)和库链接起来。
这个格式也是固定的,照着文档抄就行了。请看上面 find_package 的截图。
----------------------------------------------------------------------------------------------------------------------------------
下面是 main.cpp 中的代码,我们来试试前面的配置是否正确。 ,
#include <QApplication> #include <QWidget> #include <QHBoxLayout> #include <QPushButton>
int main(int argc, char** argv)
{ // 这个 App 和 Widgets 在代码上不直接引用 // 但它是必须的,它会开启主消息循环 QApplication app(argc, argv); // 准备主窗口 QWidget window; // 窗口标题 window.setWindowTitle("穷屌丝应用程序"); // 设置窗口大小 window.resize(400, 300); // 控件 QPushButton *btn1 = new QPushButton("第一个按钮"); QPushButton *btn2 = new QPushButton("第二个按钮"); // 布局 QHBoxLayout *layout = new QHBoxLayout(&window); // 将控件放入布局中 layout -> addWidget(btn1, 2); layout -> addWidget(btn2, 1); // 显示窗口 window.show(); // 别忘了这一行,正式启动程序 return app.exec(); // 调用静态的也行 //return QApplication::exec(); }
QApplication 类用于启动应用程序的主消息循环,它不需要显式引用 Widget 对象。调用 exec 方法正式开始消息循环。这个方法会一直循环,直到应用程序退出(主窗口/根 Widget 被关闭)才会返回。若无错误,就返回 0 ,这个返回值可以直接沿着 main 函数返回。
注意,所有初始化(创建窗口,放置控件等)代码必须在 exec 方法之前调用。exec 方法一旦调用,除非应用程序退出,否则是不会返回的。所以不要在 exec 之后写任何代码(清理代码除外)。
QWidget 是众多 UI 元素/控件的基类,直接使用它可以作为应用程序的窗口——就是一个空白窗口。setWindowTitle 方法用来设置窗口标题栏上的文本;resize 方法调整窗口的大小;show 方法显示窗口。
QHBoxLayout 是一个布局类,用来布局窗口中控件的位置。它指的是 UI 元素沿水平方向排列。这个 Layout 类似于 WPF 中的 StackPanel。嗯,相信你也猜到,要垂直布局,就用 QVBoxLayout 类。如果想向 StackPanel 那样,可以通过设置来控制水平或垂直方向,可以用 QBoxLayout,通过 setDirection 方法可以设置:从左到右、从右到左、从上到下、从下到上。
QPushButton 就是常见的按钮。
在 Qt 应用程序中,new 出来的指针不一定要 delete / free 的。因为它有个引用树的概念,会自动释放指针所引用的东西。前提是这些对象是连接到 QObject 上的。比如窗口是 QWidget ,放在窗口内的控件元素如果以窗口为父对象,就像上面那个例子,里面的 QHBoxLayout、QPushButton 等,是连接到 QWidget 上的,所以不需要 delete 指针,它会自动释放。
我们 build 一下这个项目,然后运行它。
注意看 VS Code 底部的状态栏,你能找到这两个按钮。
如果没有问题,就能看到应用程序窗口了。
在 Linux 上的编译和配置与 Windows 上差不多的。注意先安装 g++,选这个编译的话可避免各种灵异事件。老周在 Ubuntu 上试验时,曾经遇到过一次灵异事件,至今无法解释。编译 Qt6 源代码顺利完成,写一个 app 试了下也能运行起来。但是,系统重启后就进不了系统了,除了 root 帐户外,所有帐户都无权限登录。切换到 init 2 登录也不行,一登录就会被弹出来。就是除 root 外所有用户都没有任何权限,连登录的权限都没有。这现象无法解释,因为那次老周成功登入系统后只编译了 Qt6 源码,写了个测试 app,也没做别的事,重启后就挂了。