目录

Qt-6-与-Qt-5-存在的兼容性差异

Qt 6 与 Qt 5 存在的兼容性差异

之前有提到。我的是Qt5,我朋友的是Qt 6,由于版本不兼容问题,在迁移时会有问题。所以这一我们说说这两个的区别。(

正文开始喽!

https://i-blog.csdnimg.cn/direct/265ae56ffb5f4488b788043a3362ee3c.png

总结来说:Qt5迁移至 Qt 6 需:1. 破坏性变更(必须修改代码)2. 模块和功能的变化3. 构建系统的变化

一、 破坏性变更(需要修改代码)

这些是您在将项目从 Qt 5 迁移到 Qt 6 时最可能遇到并必须修改代码的地方。

1. 对 C++ 标准的要求
  • Qt 5: 最低要求 C++11,但大部分模块仍兼容 C++98。
  • Qt 6强制要求 C++17 标准。这意味着您的编译器和代码都必须支持 C++17。这是 Qt 6 现代化改造的基础。
2. 图形架构的重大改变

这是最核心的差异之一,主要影响与图形渲染相关的代码(尤其是自定义的 QQuickItem 或使用 QPainter 的场景)。

  • Qt 5: 支持多种后端,如 OpenGL、DirectX、Software(软件渲染)。在 Qt Quick 2 中,场景图(Scene Graph)是基于 OpenGL 的。

  • Qt 6: 引入了 RHI(Rendering Hardware Interface) 抽象层。

    • 是什么:RHI 是一个位于 Qt Quick 场景图和具体图形 API(如 Vulkan、Metal、Direct3D、OpenGL)之间的薄抽象层。

    • 为什么:为了实现跨平台图形后端的统一和最佳性能(默认在 macOS 上使用 Metal,在 Windows 上使用 DirectX 12/Vulkan,在 Linux 上使用 Vulkan/OpenGL)。

    • 影响

      • 所有直接使用 OpenGL 调用的代码(例如 QOpenGLFunctionsQOpenGLFramebufferObjectQOpenGLShaderProgram)都需要重写,以使用 QRhi 及其相关类(如 QRhiTextureQRhiRenderBuffer 等)。
      • 自定义的 QQuickItem 或 QQuickFramebufferObject 需要适配新的渲染路径。
    • 兼容方案:Qt 6 提供了 rhi 模块和大量示例来展示如何在新架构下进行渲染。

3. QString 相关变化
  • QString::midQString::leftQString::right:

    • Qt 5: 返回 QString
    • Qt 6: 返回 QStringView。如果您需要 QString,可能需要显式构造或使用其他方法。
  • QStringRef 被移除:由 QStringView 替代。所有使用 QStringRef 的代码都需要替换。

4. QML 注册类型的变化
  • Qt 5: 使用 qmlRegisterType 函数族进行注册。

  • Qt 6强烈推荐使用新的宏 QML_ELEMENT 和 QML_NAMED_ELEMENT(<name>) 在类声明中直接注册。虽然旧的函数仍然存在,但新方式更简洁、更易于维护。

    • Qt 5:
      
      // main.cpp
      qmlRegisterType<MyObject>("MyModule", 1, 0, "MyObject");
      
      Qt 6:
      
      // myobject.h
      #include <QtQml/qqmlregistration.h>
      class MyObject : public QObject {
          Q_OBJECT
          QML_ELEMENT // 自动使用类名
          // 或 QML_NAMED_ELEMENT("MyObject") // 自定义名称
          ...
      };
    • 然后在 CMake 中使用 qt6_add_qml_module 或在 QMake 中正确配置。
5. 容器类迭代器的行为变化
  • Qt 5QMapQHashQSet 等的迭代器行为类似于 std::mapit.key() 和 it.value() 用于访问键值对。

  • Qt 6: 为了与 C++ STL 保持一致,迭代器解引用(*it)现在返回的是 ,而不是一个键值对。

    • 对于 QMap 和 QHash*it 等价于 it.value()

    • 要获取键,仍然需要使用 it.key()

    • 这会影响基于范围的 for 循环:

      
      QMap<int, QString> map;
      // Qt 5 方式 (在Qt 6中错误)
      for (auto &pair : map) {
          // pair 是 QPair<int, QString> 或类似物
          int key = pair.key;   // 错误
          QString value = pair.value; // 错误
      }
      // Qt 5/6 通用正确方式
      for (auto it = map.begin(); it != map.end(); ++it) {
          int key = it.key();
          QString value = it.value(); // 或 *it
      }
      // Qt 6 基于范围for循环的正确方式
      for (auto &key : map.keys()) {
          QString value = map.value(key);
      }
      for (auto &value : map) { // *it 就是value,所以可以直接遍历值
          // ...
      }

二、 模块和功能的变化

1. 模块的移除和拆分

许多在 Qt 5 中处于“废弃”状态的模块在 Qt 6 中被正式移除。如果需要它们,必须单独安装或寻找替代方案。

  • 被移除的模块

    • QtScript: 已废弃,推荐使用 QJSEngine(在 QtQml 中)。
    • QtXmlPatterns: 已废弃,推荐使用 QXmlStreamReader 或第三方库。
    • QtQuick1 / QtDeclarative: QML 1.0 已被淘汰。
    • QtWebKit: 已被 QtWebEngine 取代(但 QtWebEngine 本身在 Qt 6.4 之前是附加模块,需要单独安装)。
    • QtQuickControls1: 已被 Qt Quick Controls 2 取代。
  • 变为附加模块(需要单独安装):

    • QtWebEngine: 提供浏览器功能。
    • QtSerialPortQtBluetoothQtSensors 等许多不属于核心框架的模块都变成了附加模块。
2. 新的核心模块
  • QtCore5Compat: 这是一个至关重要的兼容性模块。它包含了许多从 Qt 5 核心模块中移除但为了兼容性而保留的类,例如:

    • QRegExp (推荐使用 QRegularExpression)
    • QTextCodec 及其子类
    • QStringRef (已被 QStringView 取代)
    • 旧版本的 QDateTime API
    • 如果您遇到 QRegExp 等类找不到链接的错误,通常需要在 .pro 文件(QT += core5compat)或 CMakeLists.txtfind_package(Qt6 COMPONENTS Core5Compat))中添加这个模块。
3. API 的清理和废弃

许多在 Qt 5 中被标记为“废弃”的旧 API 在 Qt 6 中被彻底移除。编译器会直接报错。

  • 常见例子

    • QColor::light() / QColor::dark() -> 使用 QColor::lighter() / QColor::darker()
    • qVariantFromValue() -> 使用 QVariant::fromValue()
    • QFontMetrics::width() -> 使用 QFontMetrics::horizontalAdvance()

三、 构建系统的变化

1. QMake 到 CMake 的转变
  • Qt 5: 主要支持和推荐使用 QMake (.pro 文件)。
  • Qt 6官方强烈推荐并主要支持使用 CMake。虽然仍然支持 QMake,但所有新的特性和开发都优先面向 CMake。Qt 官方提供的许多工具和集成(如用于 QML 的 qt6_add_qml_module)都是为 CMake 设计的。
2. 新的 QML 模块构建系统
  • 在 Qt 6 中,使用 CMake 管理 QML 模块、资源(qmldirqrc 文件)变得更加简单和强大,通过 qt6_add_qml_module 宏可以一站式处理类型注册、资源打包和模块发现。

迁移建议和总结

  1. 检查编译器:确保您的编译器支持 C++17。

  2. 使用端口工具:运行 qt6_porting_tools 中的 configure 和 cmake 脚本来分析您的代码,它们能识别出许多常见的兼容性问题。

  3. 逐模块处理

    • 首先处理核心模块(QtCore, QtGui, QtWidgets)的编译错误(如废弃的 API)。
    • 然后重点关注图形相关代码(OpenGL -> RHI)。
    • 接着处理 QML 注册和 QML 相关代码。
  4. 添加 Core5Compat 模块:如果遇到 QRegExp 等链接错误,这是最快的解决方案。

  5. 查阅官方文档:Qt 官方提供了非常详细的   指南,这是最权威的参考。