之前有提到。我的是Qt5,我朋友的是Qt 6,由于版本不兼容問題,在遷移時會有問題。所以這一我們說說這兩個的區別。(
正文開始嘍!
總結來說: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 調用的代碼(例如?
QOpenGLFunctions
,?QOpenGLFramebufferObject
,?QOpenGLShaderProgram
)都需要重寫,以使用?QRhi
?及其相關類(如?QRhiTexture
,?QRhiRenderBuffer
?等)。 -
自定義的?
QQuickItem
?或?QQuickFramebufferObject
?需要適配新的渲染路徑。
-
-
兼容方案:Qt 6 提供了?
rhi
?模塊和大量示例來展示如何在新架構下進行渲染。
-
3.?QString 相關變化
-
QString::mid,?QString::left,?QString::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_OBJECTQML_ELEMENT // 自動使用類名// 或 QML_NAMED_ELEMENT("MyObject") // 自定義名稱... };
-
然后在 CMake 中使用?
qt6_add_qml_module
?或在 QMake 中正確配置。
-
5.?容器類迭代器的行為變化
-
Qt 5:?
QMap
,?QHash
,?QSet
?等的迭代器行為類似于?std::map
,it.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
: 提供瀏覽器功能。 -
QtSerialPort
,?QtBluetooth
,?QtSensors
?等許多不屬于核心框架的模塊都變成了附加模塊。
-
2.?新的核心模塊
-
QtCore5Compat
: 這是一個至關重要的兼容性模塊。它包含了許多從 Qt 5 核心模塊中移除但為了兼容性而保留的類,例如:-
QRegExp
?(推薦使用?QRegularExpression
) -
QTextCodec
?及其子類 -
QStringRef
?(已被?QStringView
?取代) -
舊版本的?
QDateTime
?API -
如果您遇到?
QRegExp
?等類找不到鏈接的錯誤,通常需要在?.pro
?文件(QT += core5compat)或?CMakeLists.txt
(find_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 模塊、資源(
qmldir
,?qrc
?文件)變得更加簡單和強大,通過?qt6_add_qml_module
?宏可以一站式處理類型注冊、資源打包和模塊發現。
遷移建議和總結
-
檢查編譯器:確保您的編譯器支持 C++17。
-
使用端口工具:運行?
qt6_porting_tools
?中的?configure
?和?cmake
?腳本來分析您的代碼,它們能識別出許多常見的兼容性問題。 -
逐模塊處理:
-
首先處理核心模塊(QtCore, QtGui, QtWidgets)的編譯錯誤(如廢棄的 API)。
-
然后重點關注圖形相關代碼(OpenGL -> RHI)。
-
接著處理 QML 注冊和 QML 相關代碼。
-
-
添加 Core5Compat 模塊:如果遇到?
QRegExp
?等鏈接錯誤,這是最快的解決方案。 -
查閱官方文檔:Qt 官方提供了非常詳細的?Porting from Qt 5 to Qt 6?指南,這是最權威的參考。