1. 为什么 Qt 6.8 LTS 值得你花时间折腾
Qt 6.8 是 Qt 6 系列里第二个长期支持版本,上一个 LTS 是 6.2,中间隔了差不多三年。这三年里 Qt 6 从“勉强能用”一路打磨到“可以放心上项目”,6.8 基本算是 Qt 6 真正成熟的标志性节点。如果你手上还有一堆 Qt 5.15 的老项目在跑,或者正纠结新项目到底选 Qt 5 还是 Qt 6,那这个版本值得认真看一看。
我自己从 Qt 5.12 一路用到 6.8,踩过的坑不算少。早期 Qt 6 的坑主要集中在第三方模块缺失、构建系统切换(qmake 到 CMake)、QML 编译器不稳定这几块。到了 6.8,这些问题基本都有了明确的解决方案,尤其是 CMake 生态已经非常成熟,Qt Creator 对 CMake 项目的支持也顺手了很多。
这篇文章会围绕 Qt 6.8 LTS 和 Qt for MCUs 2.9 两个发布来展开,重点讲清楚几件事:6.8 到底带来了哪些实质性变化、哪些模块值得关注、从 Qt 5 迁移过来要注意什么、Qt for MCUs 2.9 引入 Zephyr RTOS 支持意味着什么、以及在实际项目里怎么落地。内容会偏实操,尽量把“为什么这么做”讲透,而不是只列一堆新特性清单。
适合谁看?如果你是用 Qt 做桌面端、嵌入式 HMI、工业上位机的开发者,或者正在评估 Qt 6 是否值得升级的技术负责人,这篇内容应该能帮你省下不少查文档的时间。如果你刚接触 Qt,也可以看,但建议先把 Qt 5 或 Qt 6 的基础过一遍再回来读迁移和 MCUs 部分。
2. Qt 6.8 LTS 核心变化拆解
2.1 LTS 意味着什么,和普通版本差在哪
先把这个概念说清楚,因为很多人对 LTS 有误解。Qt 的版本节奏是:每年两个大版本(比如 6.7、6.8),其中某些版本会被标记为 LTS。LTS 版本的核心区别在于商业支持周期——商业用户可以获得长达 5 年的补丁支持,而普通版本通常只有 6 个月左右的维护窗口。
但要注意,LTS 对开源用户的意义没那么大。开源版本的安全补丁和 bug 修复通常只覆盖到下一个版本发布后的一段时间,不会真的给你维护 5 年。所以如果你是开源用户,选 LTS 的主要理由是稳定性——LTS 版本在发布前会经过更长时间的测试,API 冻结更早,不会出现大版本里那种“这个版本改了接口下个版本又改回去”的情况。
Qt 6.8 作为 LTS,API 层面基本冻结,后续 6.8.x 系列只会做 bug 修复和安全补丁,不会引入破坏性变更。这对企业项目来说很重要——你可以放心地把 6.8.0 作为基线,后续小版本升级风险很低。
2.2 图形渲染与 RHI 的持续演进
Qt 6 最大的架构变化之一就是引入了 RHI(Rendering Hardware Interface),把图形渲染从 OpenGL 抽象出来,支持 Vulkan、Metal、Direct3D 11/12 等多种后端。6.8 在 RHI 上继续加码,几个值得关注的点:
Vulkan 后端成熟度提升。早期 Qt 6 的 Vulkan 后端问题不少,尤其是多线程渲染场景下容易出现同步问题。6.8 里 Vulkan 后端的稳定性已经可以用于生产环境,如果你做的是高性能可视化或者需要精细控制 GPU 的场景,可以试试强制指定 Vulkan 后端。
Direct3D 12 支持增强。Windows 平台上 D3D12 的性能优势在 6.8 里体现得更明显,尤其是配合 QRhi 做自定义渲染管线的时候。不过要注意,D3D12 对驱动版本有要求,老机器上可能回退到 D3D11。
OpenGL 仍然是默认后端。虽然 Qt 在推新后端,但 OpenGL 依然是兼容性最好的选择。如果你不追求极致性能,保持默认就行,别为了用新后端而用新后端。
这里有个实操经验:切换 RHI 后端可以通过环境变量QSG_RHI_BACKEND来指定,比如QSG_RHI_BACKEND=vulkan。但不要在生产环境里随便切,一定要在目标机器上充分测试。我见过有人本地用 Vulkan 跑得好好的,部署到客户机器上因为驱动问题直接黑屏。
2.3 Qt Quick 与 QML 的性能改进
QML 的性能一直是大家关心的点。6.8 在 QML 引擎上做了几项优化:
QML 编译器(qmlcachegen/qmlsc)的编译速度提升。大项目里 QML 文件动辄几百上千个,编译时间是个痛点。6.8 优化了编译管线,实测下来大型项目的 QML 编译时间能缩短 20% 到 30%。这个提升在 CI 环境里特别明显,能省不少构建时间。
QML 类型注册的改进。以前用qmlRegisterType注册 C++ 类型,现在更推荐用QML_ELEMENT宏配合 CMake 的qt_add_qml_module。6.8 里这套机制更完善了,类型注册的报错信息也更清晰。如果你还在用老式的qmlRegisterType,建议趁迁移的时候一起改掉。
绑定(Binding)性能优化。QML 的属性绑定是它的核心特性,但绑定过多会导致性能问题。6.8 优化了绑定的求值机制,减少了不必要的重算。不过这只是缓解,根本的解决办法还是减少绑定层级、避免在绑定里做复杂计算。
2.4 网络与串口模块的坑
热词里出现了unknown module in qt:serialport和unknown module(s) in qt: serialport,说明不少人在用串口模块时遇到了问题。这个错误通常出现在 CMake 项目里,原因是Qt6::SerialPort模块没有被正确 find 到。
正确的 CMake 写法是这样的:
find_package(Qt6 REQUIRED COMPONENTS Core SerialPort) target_link_libraries(myapp PRIVATE Qt6::Core Qt6::SerialPort)如果你用的是 qmake,对应的是:
QT += serialport出现unknown module的常见原因有几个:一是 Qt 安装时没有勾选 SerialPort 模块(在线安装器里默认可能不装);二是 CMake 的find_package没有包含 SerialPort 组件;三是环境变量CMAKE_PREFIX_PATH没指向正确的 Qt 安装路径。排查的时候按这个顺序查,基本能定位到问题。
网络模块方面,6.8 对QNetworkAccessManager做了一些内部优化,HTTP/2 的支持更稳定了。如果你做的是需要大量网络请求的应用,建议升级后测一下并发场景。
2.5 构建系统:CMake 已经是唯一正确答案
Qt 6 全面转向 CMake,qmake 虽然还能用,但官方已经明确表示 qmake 不再是主要构建系统。6.8 里 CMake 的集成更加完善,qt_add_executable、qt_add_library、qt_add_qml_module这些命令已经非常成熟。
从 qmake 迁移到 CMake 是很多老项目升级 Qt 6 时最大的工作量。我的建议是不要试图在 qmake 里硬撑,直接切 CMake。虽然前期要花时间改构建脚本,但后续维护成本会低很多。而且 Qt Creator 对 CMake 项目的支持已经很好,代码补全、调试、部署都没问题。
一个典型的 Qt 6 CMake 项目结构大概是这样:
cmake_minimum_required(VERSION 3.16) project(MyApp VERSION 1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Quick) qt_add_executable(MyApp main.cpp mainwindow.cpp mainwindow.h ) target_link_libraries(MyApp PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Quick )注意CMAKE_AUTOMOC、CMAKE_AUTORCC、CMAKE_AUTOUIC这三个开关,它们负责自动处理 moc、资源文件和 UI 文件。Qt 6 里这些自动化机制比 Qt 5 更可靠,但前提是你要正确设置。
3. 从 Qt 5 迁移到 Qt 6.8 的实操路线
3.1 迁移前的评估:哪些项目该迁,哪些不该迁
不是所有项目都值得迁移。先做个评估:
适合迁移的情况:新项目、还在活跃开发的项目、需要用到 Qt 6 新特性(比如更好的 QML、RHI、新模块)的项目、需要长期维护的项目。
不适合迁移的情况:已经进入维护期、只做 bug 修复的老项目;依赖大量 Qt 5 专有模块且这些模块在 Qt 6 里没有替代方案的项目;团队没有精力做迁移测试的项目。
迁移的成本主要在几个方面:构建系统改造(qmake 到 CMake)、废弃 API 替换、第三方库兼容性、QML 语法调整。小项目可能几天搞定,大项目可能要几周甚至几个月。
3.2 废弃 API 的替换清单
Qt 6 移除或废弃了不少 Qt 5 的 API,这里列几个高频的:
| Qt 5 API | Qt 6 替代方案 | 说明 |
|---|---|---|
QString::split的某些重载 | 使用Qt::SplitBehavior | 枚举名变了 |
QTextStream的setCodec | setEncoding | 编码处理重构 |
QRegExp | QRegularExpression | QRegExp 已移除 |
QDesktopWidget | QScreen | 多屏处理方式变了 |
QApplication::desktop() | QGuiApplication::primaryScreen() | 同上 |
QLinkedList | std::list或QList | QLinkedList 已移除 |
QVector | QList | Qt 6 里 QVector 就是 QList 的别名 |
QRegExp到QRegularExpression是最常见的迁移点。两者的语法有差异,尤其是贪婪匹配和分组引用的写法。迁移时不能简单替换类名,要逐个检查正则表达式。
3.3 QML 迁移的注意事项
QML 方面,Qt 6 的变化也不小:
版本号可以省略了。Qt 6 里import QtQuick 2.15这种写法可以简化为import QtQuick,不写版本号默认导入最新版本。建议迁移时统一去掉版本号,避免版本混乱。
QtQuick.Controls的样式系统变了。Qt 5 里的QtQuick.Controls 1.x和2.x是两套不同的实现,Qt 6 只保留了 2.x 的演进版本。如果你还在用 Controls 1,迁移工作量会比较大。
QtGraphicalEffects被移除。这个模块在 Qt 6 里没有了,替代方案是用Qt5Compat.GraphicalEffects(兼容模块)或者自己用 ShaderEffect 实现。长期来看建议自己实现或者找替代库。
QtQuick.Window的调整。窗口相关的 API 有一些变化,尤其是Screen相关的属性。
3.4 第三方库兼容性排查
迁移前一定要排查第三方库。常见的几类:
Halcon。热词里有qt怎么调用halcon,说明做机器视觉的同行不少。Halcon 对 Qt 6 的支持要看版本,较新的 Halcon 版本已经支持 Qt 6,老版本可能只支持 Qt 5。迁移前先确认 Halcon 版本。
FFmpeg。热词里有qt + ffmpeg + adb学习教程。FFmpeg 本身和 Qt 版本无关,但集成方式可能受影响。主要是 CMake 的 find_package 配置要调整。
串口/网络库。如果你用的是 Qt 自带的QtSerialPort、QtNetwork,迁移相对简单。如果用的是第三方库(比如 libmodbus、libserial),要确认它们对 Qt 6 的兼容性。
报表库。热词里有qt limereport 实现报表打印。LimeReport 对 Qt 6 的支持要看版本,老版本可能不兼容。类似的报表库还有 QPrinter、QtRPT 等,迁移前都要确认。
4. Qt for MCUs 2.9 与 Zephyr RTOS 的落地实践
4.1 Qt for MCUs 是什么,解决什么问题
Qt for MCUs 是 Qt 专门为微控制器(MCU)做的轻量级图形框架。它和桌面版 Qt 是两套东西——桌面版 Qt 跑在 Linux/Windows 上,依赖操作系统;Qt for MCUs 可以直接跑在裸机或者 RTOS 上,资源占用极小,适合那些内存只有几百 KB、主频几十 MHz 的 MCU。
它的核心价值在于:让嵌入式 HMI 开发也能用 QML。传统 MCU 上做界面,要么用段码屏,要么用简单的图形库(比如 emWin、LVGL),开发效率低、效果差。Qt for MCUs 让你用 QML 描述界面,然后编译成适合 MCU 的二进制,兼顾开发效率和运行性能。
热词里有linux跑qt还是lvgl,这其实是个常见的选择题。简单说:如果你的硬件跑得动 Linux(比如 Cortex-A 系列),用桌面版 Qt;如果是 Cortex-M 系列 MCU,资源紧张,用 Qt for MCUs 或者 LVGL。LVGL 更轻量但生态和工具链不如 Qt 完善,Qt for MCUs 开发体验更好但资源占用略高。
4.2 Zephyr RTOS 支持意味着什么
Qt for MCUs 2.9 最大的变化是增加了对 Zephyr RTOS 的支持。Zephyr 是一个开源的实时操作系统,在嵌入式领域越来越流行,尤其是 Nordic、NXP、Espressif 等厂商的芯片上。
之前 Qt for MCUs 主要支持 FreeRTOS 和裸机,现在加上 Zephyr,意味着你可以:
- 在 Zephyr 项目里直接集成 Qt for MCUs 做界面
- 利用 Zephyr 的设备驱动、网络协议栈、电源管理
- 用 Zephyr 的构建系统(west + CMake)管理整个项目
这对已经在用 Zephyr 的团队来说是好事——不用为了做界面而换 RTOS。对还没选 RTOS 的团队来说,Zephyr + Qt for MCUs 也是一个值得考虑的方案。
4.3 在 Zephyr 上跑 Qt for MCUs 的实操步骤
这里给一个基于常见实践的集成流程。具体细节可能因芯片和开发板而异,但整体思路是通用的。
第一步:准备 Zephyr 开发环境。用 west 工具初始化 Zephyr 工作区:
west init ~/zephyrproject cd ~/zephyrproject west update然后安装 Zephyr SDK 和 Python 依赖。这一步按 Zephyr 官方文档走就行。
第二步:获取 Qt for MCUs。Qt for MCUs 是商业授权产品,需要从 Qt 官网下载。下载后解压到某个目录,比如~/QtForMCUs。
第三步:配置 Qt for MCUs 的 Zephyr 后端。Qt for MCUs 提供了一个 Zephyr 的 board 定义和驱动适配层。你需要把 Qt for MCUs 的 Zephyr 模块路径加到ZEPHYR_EXTRA_MODULES环境变量里:
export ZEPHYR_EXTRA_MODULES=~/QtForMCUs/zephyr第四步:创建应用项目。用 Qt for MCUs 提供的模板创建项目,然后在CMakeLists.txt里指定 Zephyr 作为目标平台。Qt for MCUs 的构建系统会调用 Zephyr 的构建流程,最终生成可烧录的固件。
第五步:编译和烧录。用 west build 编译,然后用 west flash 烧录到开发板。Qt for MCUs 的 QML 代码会被编译成 C++ 代码,再和 Zephyr 一起编译成固件。
这里有个关键点:Qt for MCUs 的 QML 是编译期处理的,不是运行期解释的。这意味着 QML 里的动态特性(比如动态创建对象、复杂的绑定)支持有限。写 QML 的时候要按 Qt for MCUs 的规范来,不能照搬桌面版 QML 的写法。
4.4 资源受限环境下的优化技巧
MCU 上资源紧张,优化是必须的。几个实操经验:
图片资源用 RLE 或自定义压缩。Qt for MCUs 支持图片压缩,但压缩率高的格式解码慢。要在压缩率和解码速度之间找平衡。实测下来,简单的 RLE 压缩对图标类图片效果不错。
减少图层数量。MCU 的 GPU(如果有的话)性能有限,图层多了会卡。尽量把静态内容合并到一个图层,只把需要频繁更新的部分单独分层。
动画用硬件加速。如果 MCU 支持 DMA2D 或者类似的 2D 加速器,一定要用上。Qt for MCUs 有对应的后端适配,配置对了能大幅提升动画流畅度。
字体裁剪。中文字体动辄几 MB,MCU 上放不下。要用字体裁剪工具只保留用到的字符。Qt for MCUs 提供了字体转换工具,可以把 TTF 转成适合 MCU 的格式。
内存池预分配。MCU 上不要用动态内存分配,容易碎片化。Qt for MCUs 支持静态内存池配置,把 UI 对象需要的内存提前分配好。
5. 常见问题与排查技巧实录
5.1 Qt 6.8 安装与模块缺失问题
问题:CMake 报unknown module(s) in qt: serialport
这个前面提过,核心原因是模块没装或者没 find 到。排查步骤:
- 检查 Qt 安装目录下有没有
Qt6SerialPort相关的库文件。如果没有,用 Qt 维护工具(MaintenanceTool)补装 SerialPort 模块。 - 检查 CMakeLists.txt 里
find_package是否包含了 SerialPort 组件。 - 检查
CMAKE_PREFIX_PATH是否指向正确的 Qt 安装路径。 - 如果用的是 IDE(比如 Qt Creator),检查 Kit 配置里的 Qt 版本是否正确。
问题:cannot mix incompatible Qt library (5.15.3) with this library (5.15.2)
这是典型的版本混用问题。系统里装了多个 Qt 版本,运行时链接到了错误的库。解决办法:
- 检查
LD_LIBRARY_PATH(Linux)或PATH(Windows)里是否有多个 Qt 路径。 - 用
ldd(Linux)或dumpbin /dependents(Windows)查看可执行文件实际链接的 Qt 库。 - 清理环境变量,确保只保留目标 Qt 版本的路径。
- 如果是打包发布,用
windeployqt(Windows)或linuxdeployqt(Linux)自动收集依赖。
5.2 绘图与性能相关问题
问题:QChart 曲线刷新卡顿,能不能放到另一个线程
可以,但要注意 QChart 不是线程安全的。正确的做法是:在后台线程计算数据,然后通过信号槽把数据传到主线程,在主线程更新图表。不要直接在后台线程操作 QChart 对象。
如果数据量很大,考虑用QChart::setAnimationOptions(NoAnimation)关掉动画,或者用QLineSeries::replace批量替换数据点,而不是逐个 append。
问题:Qt 绘图效率比较,QPainter 和 QML 哪个快
看场景。QPainter 适合复杂的自定义绘制,尤其是需要精细控制每个像素的场景。QML 适合声明式的 UI,配合场景图(Scene Graph)可以利用 GPU 加速。如果是大量简单图形,QML 通常更快;如果是复杂路径绘制,QPainter 可能更合适。
实测下来,QML 的场景图在 GPU 加速下,几千个简单图元的渲染可以轻松跑到 60fps。QPainter 在 CPU 上绘制同样数量的图元,可能只有 20-30fps。但 QPainter 配合 OpenGL 后端也能加速,只是配置麻烦一些。
5.3 开发环境配置问题
问题:VS Code + Qt 5.9 怎么配置
Qt 5.9 比较老了,建议至少升到 Qt 5.15。如果必须用 5.9,配置步骤:
- 安装 Qt 5.9 和对应的编译器(MinGW 或 MSVC)。
- VS Code 安装 C/C++ 扩展和 Qt 相关扩展(比如 Qt Tools)。
- 配置
c_cpp_properties.json,把 Qt 的 include 路径加进去。 - 配置
tasks.json,用 qmake + make 或者 CMake 构建。 - 配置
launch.json,设置调试器路径和环境变量。
说实话,VS Code 配 Qt 不如直接用 Qt Creator 省事。Qt Creator 对 Qt 项目的支持是原生的,代码补全、调试、UI 设计、部署都集成好了。除非你有特殊理由必须用 VS Code,否则建议用 Qt Creator。
问题:Qt Creator 代码对齐快捷键不好用
Qt Creator 默认的代码格式化快捷键是Ctrl+I(对齐选中行)。如果不好用,检查:
- 是不是和输入法快捷键冲突了。
- 是不是在设置里改了快捷键映射。
- 可以自定义格式化规则:工具 -> 选项 -> C++ -> 代码风格,配置好之后用
Ctrl+Shift+I格式化整个文件。
5.4 打包与发布问题
问题:Qt 发布软件,怎么打包依赖
Windows 上用windeployqt:
windeployqt --release --no-translations myapp.exeLinux 上用linuxdeployqt或者手动收集依赖。macOS 上用macdeployqt。
注意几点:一是要包含 Qt 的插件(platforms、imageformats、styles 等),windeployqt默认会带上;二是如果用了 OpenSSL,要手动把 libssl 和 libcrypto 拷进去;三是如果用了第三方库,要确认它们的依赖也被打包了。
问题:Qt 国内镜像下载慢
Qt 官方下载服务器在国内访问确实慢。可以用国内镜像,比如清华、中科大、阿里云的镜像。在线安装器可以在设置里配置镜像源。离线安装包也可以从镜像站下载。
不过要注意,镜像站可能不是实时同步的,新版本发布后可能要等几天才有。如果急着用新版本,还是得从官方源下。
5.5 常见问题速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
unknown module in qt:serialport | 模块未安装或未 find | 补装模块,检查 CMake find_package |
cannot mix incompatible Qt library | 多版本 Qt 混用 | 清理环境变量,统一 Qt 版本 |
| QML 编译报错 | QML 语法不兼容 Qt 6 | 检查 import 语句,去掉版本号 |
| 程序启动黑屏 | RHI 后端不兼容 | 切回 OpenGL 后端 |
| 串口打不开 | 权限问题(Linux) | 把用户加到 dialout 组 |
| 打包后缺少 DLL | 依赖未收集 | 用 windeployqt 自动收集 |
| QChart 刷新卡顿 | 主线程阻塞 | 数据计算放后台线程,主线程更新 UI |
| 中文显示乱码 | 编码设置问题 | 统一用 UTF-8,设置 QTextStream 编码 |
6. 升级决策与长期维护建议
6.1 现在升级还是再等等
Qt 6.8 是 LTS,API 稳定,bug 修复有保障。如果你还在 Qt 5.15,现在是个不错的升级时机。但升级前要评估:
- 项目依赖的第三方库是否支持 Qt 6。
- 团队是否有时间做迁移和测试。
- 是否有必须用 Qt 6 新特性的需求。
如果项目稳定、没有新需求、团队精力有限,可以再等等。但要注意 Qt 5.15 的开源支持已经结束,后续安全漏洞不会修复,长期来看还是要升。
6.2 版本锁定与升级策略
生产项目建议锁定具体版本,比如6.8.0,不要用6.8.x这种浮动版本。升级时先在开发环境验证,再上测试环境,最后上生产。每次升级都要跑完整的回归测试,尤其是 UI 和图形相关的部分。
如果用的是商业版,可以订阅 Qt 的 LTS 支持,获得官方补丁和技术支持。开源版的话,关注 Qt 的 bug tracker,及时应用社区补丁。
6.3 嵌入式项目的选型建议
嵌入式 HMI 选型,我的经验是:
- Cortex-A + Linux:用桌面版 Qt 6.8,功能最全,开发效率最高。
- Cortex-M + RTOS:用 Qt for MCUs,配合 FreeRTOS 或 Zephyr。
- 资源极度受限:考虑 LVGL 或 emWin,Qt for MCUs 虽然轻量但也有最低资源要求。
- 需要功能安全认证:Qt for MCUs 有安全认证版本,但成本较高,要提前评估。
Zephyr + Qt for MCUs 的组合适合那些已经在用 Zephyr 或者计划用 Zephyr 的团队。Zephyr 的生态在快速成长,长期来看是个不错的选择。但要注意 Zephyr 的学习曲线,尤其是设备树(Device Tree)和 Kconfig 那套东西,不熟悉的话前期会比较痛苦。
6.4 我个人的一些实操体会
用了这么多年 Qt,有几个体会比较深:
不要追新版本。新版本发布后至少等一两个小版本再上生产,让社区先踩坑。6.8.0 刚发布时可能有些边角问题,6.8.1 或 6.8.2 会更稳。
构建系统早切早好。qmake 到 CMake 的迁移越早做越好,拖得越久包袱越重。新项目直接用 CMake,别犹豫。
QML 和 C++ 的边界要清晰。QML 负责 UI,C++ 负责逻辑,不要混着写。QML 里做复杂计算是性能杀手,C++ 里做 UI 布局是自找麻烦。
测试要覆盖图形部分。Qt 的图形渲染在不同平台、不同驱动上表现可能不一样。自动化测试要包含截图对比,确保 UI 没有意外变化。
文档和社区是最好的老师。Qt 的官方文档质量很高,遇到问题先查文档。社区方面,Qt 的论坛和 Stack Overflow 上的 Qt 标签都很活跃,大部分问题都能找到答案。
最后分享一个小技巧:如果你在迁移过程中遇到某个 API 不知道对应 Qt 6 的哪个替代,可以用 Qt 的QT_DISABLE_DEPRECATED_BEFORE宏来定位。把这个宏设成0x050F00(Qt 5.15),编译时会报出所有用到的废弃 API,然后逐个替换。这个方法比手动查文档快得多。