前言
在现代软件开发中,跨平台的图形用户界面(GUI)和可视化功能已经变得非常重要。Qt和Qt Quick(基于QML)是强大而灵活的工具,可以帮助开发者快速构建出色的应用程序。然而,当你已经有一个基于C++和CMake的工程时,将Qt和Qt Quick引入可能需要一些指导。
本教程将帮助具有C++和CMake基础知识的开发者将Qt和Qt Quick引入现有的CMake工程。我们将介绍如何设置CMakeLists.txt文件以便使用Qt模块,以及如何在C++和QML代码中实现跨语言的交互。通过本教程,你将能够将Qt和Qt Quick应用到你的项目中,创建出富有吸引力的用户界面和可视化效果。
QML简介
QML是Qt的一种声明式编程语言,用于设计和实现跨平台的用户界面。与Qt Widgets相比,QML具有以下优势:
- 简洁的语法:QML具有简洁、易读的语法,使得创建和修改用户界面变得非常直观。它允许你以更少的代码实现相同的功能,从而提高开发效率。
- 强大的动画和特效支持:QML内置了丰富的动画和特效支持,使得创建具有吸引力的用户界面变得更加容易。你可以方便地为界面元素添加动画效果,提高用户体验。
- 跨平台兼容性:QML可以很好地支持不同平台和设备,使得跨平台应用开发变得更加容易。使用QML,你可以为桌面、移动和嵌入式设备创建统一的用户界面。
- 面向对象的编程:QML支持面向对象编程,允许你创建可重用的组件和模块。这有助于提高代码的模块化和可维护性。
- 与C++的紧密集成:QML可以轻松地与C++代码进行集成,允许你在QML界面中使用C++实现的功能。这使得QML非常适合与现有的C++项目一起使用。
尽管QML具有这些优势,但它并不总是比Qt Widgets更容易实现。实际上,两者之间的难易程度取决于你的需求和经验。Qt Widgets在某些场景下可能更适用,尤其是对于传统的桌面应用程序,以及对性能要求较高的场景。
总的来说,QML在许多方面具有优势,但你应该根据项目需求和个人喜好来选择最适合的技术。如果你对QML感兴趣,我建议你尝试使用它来实现一些简单的项目,以便更好地了解它的特点和优势。
锻炼C++水平
- 使用Qt Widgets:虽然QML是一种强大的界面设计语言,但使用Qt Widgets同样可以创建出优秀的界面,同时更多地使用C++代码。通过使用Qt Widgets,你可以在实际项目中应用和提高C++编程技能。
- 将C++和QML结合:QML和C++可以很好地集成在一起。你可以使用C++编写应用程序的核心逻辑和算法,然后将这些功能暴露给QML以在用户界面中使用。这样,你既能锻炼C++编程能力,又能学习QML的使用方法。
- 参与开源项目:加入一个使用C++的开源项目,可以让你在实际项目中应用和提高C++编程技能。参与开源项目可以帮助你了解更多关于C++的最佳实践和技巧,同时还能扩展你的技术网络。
- 阅读C++相关书籍和教程:阅读高质量的C++书籍和教程可以帮助你深入了解C++语言的特性和最佳实践。一些经典的C++书籍,如《Effective C++》、《C++ Primer》和《The C++ Programming Language》,都是值得一读的好书。
- 解决编程挑战和问题:在网上寻找C++编程挑战和问题,例如LeetCode、HackerRank等平台上的编程题目。这些挑战可以帮助你锻炼编程能力,提高解决问题的速度和效率。
- 学习C++新特性:C++语言一直在不断发展,新的标准和特性会定期推出。关注并学习这些新特性,可以让你保持C++知识的更新,同时提高编程能力。
通过采取这些策略,你可以在实际项目中锻炼和提高C++编程技能。同时,学习QML可以帮助你更好地应对不同类型的项目需求,让你在软件开发领域具有更强的竞争力。祝你在C++和QML的学习过程中取得好成绩!
cmake修改方法
方式一(qt6_add_resources)
要将现有的C++ CMake工程引入Qt6环境并使用Qt和QML,你需要执行以下步骤:
- 安装Qt6:如果你还没有安装Qt6,请从官方网站下载并安装。确保你安装了Qt6的CMake模块。
- 修改CMakeLists.txt:在你的C++ CMake工程中,打开
CMakeLists.txt
文件。首先,确保找到Qt6包,然后链接到需要的Qt6模块。例如,如果你需要使用Qt6 Core、Gui和Quick模块,可以添加以下内容:
find_package(Qt6 COMPONENTS Core Gui Quick REQUIRED
- 然后,将这些模块链接到你的目标(例如,你的可执行文件):
target_link_libraries(your_target_name PRIVATE Qt6::Core Qt6::Gui Qt6::Quick)
- 添加QML文件:在工程目录下创建一个QML文件夹,将所有QML文件放在该文件夹中。然后,在
CMakeLists.txt
中使用file(GLOB ...)
命令将这些文件添加到工程中。例如:
file(GLOB QML_FILES qml/*.qml)
- 将QML文件添加到可执行文件的资源文件中:
qt6_add_resources(your_target_name "qml" PREFIX "/" FILES ${QML_FILES} )
- 创建主入口:在你的C++工程中创建一个
main.cpp
文件(如果尚未创建),并添加以下代码以设置Qt和QML环境:
#include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); }
- 注册C++类:在
main.cpp
中,使用qmlRegisterType
函数注册你的C++类,使其可以在QML中使用。例如:
qmlRegisterType<YourCppClass>("com.example.yourclassname", 1, 0, "YourCppClass");
- 然后在QML文件中,可以通过以下方式导入和使用你的C++类:
import com.example.yourclassname 1.0 YourCppClass { // ... }
- 编译和运行:现在你的C++ CMake工程已经集成了Qt6和QML,你可以编译和运行它。如果一切正常,你应该可以看到你的QML界面。
方式二 (qt_add_qml_module )
当然,你也可以使用qt_add_qml_module
函数在CMake项目中添加QML模块。这是一个简化了QML资源添加的便捷方法。下面是如何使用qt_add_qml_module
的步骤:
- 安装Qt6:如果你还没有安装Qt6,请从官方网站下载并安装。确保你安装了Qt6的CMake模块。
- 修改CMakeLists.txt:在你的C++ CMake工程中,打开
CMakeLists.txt
文件。首先,确保找到Qt6包,然后链接到需要的Qt6模块。例如,如果你需要使用Qt6 Core、Gui和Quick模块,可以添加以下内容:
find_package(Qt6 COMPONENTS Core Gui Quick REQUIRED)
- 然后,将这些模块链接到你的目标(例如,你的可执行文件):
target_link_libraries(your_target_name PRIVATE Qt6::Core Qt6::Gui Qt6::Quick)
- 添加QML文件:在工程目录下创建一个QML文件夹,将所有QML文件放在该文件夹中。
- 使用qt_add_qml_module:在
CMakeLists.txt
中,使用qt_add_qml_module
函数将QML文件添加到工程中。例如:
qt_add_qml_module(your_target_name URI com.example.yourclassname VERSION 1.0 QML_FILES qml/main.qml )
- 其中
your_target_name
是你的可执行文件的目标名称,URI
指定了模块的标识符,VERSION
设置了模块的版本,QML_FILES
列出了所有的QML文件。 - 创建主入口:在你的C++工程中创建一个
main.cpp
文件(如果尚未创建),并添加以下代码以设置Qt和QML环境:
#include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; const QUrl url(QStringLiteral("qrc:/qml/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); }
- 注册C++类:在
main.cpp
中,使用qmlRegisterType
函数注册你的C++类,使其可以在QML中使用。例如:
qmlRegisterType<YourCppClass>("com.example.yourclassname", 1, 0, "YourCppClass");
- 然后在QML文件中,可以通过以下方式导入和使用你的C++类:
import com.example.yourclassname 1.0 YourCppClass { // ...
其他相关知识
为什么会有_other_files
?
这个问题是因为 qt_add_qml_module
函数在将 QML 文件添加到项目时,会创建一个名为 _other_files
的辅助目标。这个辅助目标是用于在 Qt Creator 中显示 QML 文件和其他相关文件。这个目标对于构建过程没有影响,也不会生成任何二进制文件。它只是为了在 Qt Creator 中提供更好的文件组织和显示。
qt_standard_project_setup()
函数
qt_standard_project_setup()
函数。这个函数会在内部配置 CMake 以便为 Qt 项目生成一个更简洁的目录结构,这意味着它会自动处理 QML 模块和资源的添加,而不会生成额外的辅助目标。
qt_standard_project_setup()
函数在调用 qt_add_qml_module()
之前已经为项目配置了资源管理,所以你没有看到任何 _other_files
目标。
如果你想在自己的项目中使用类似的设置,可以尝试在调用 find_package()
和 add_executable()
之后添加 qt_standard_project_setup()
函数。这样,你可以得到一个更简洁的目录结构,同时保留 Qt Creator 的 QML 模块管理功能。
请注意,qt_standard_project_setup()
函数是 Qt 的一个实验性功能,未来版本的 Qt 可能会对其进行更改或移除。在使用这个函数时,请确保你了解其实现细节,并准备好在将来的 Qt 版本中进行必要的调整。
qt_add_qml_module()
和 qt6_add_resources()
的方式差异
qt_add_qml_module()
和 qt6_add_resources()
都可以将 QML 文件和其他资源添加到项目中,但它们的功能和目标有所不同:
qt_add_qml_module()
:
- 是为了简化 QML 模块的创建和管理而设计的。
- 自动生成 QRC 文件。
- 可以指定模块的 URI 和版本,这对于在项目中使用 QML 模块很有用。
- 会创建一个名为
_other_files
的辅助目标,用于在 Qt Creator 中显示 QML 文件和其他相关文件,以便于查看和管理。 - 更适合用于包含 QML 模块的项目,可以自动处理 QML 模块的注册和资源管理。
qt6_add_resources()
:
- 是一个更通用的函数,用于将资源(如图像、文本文件等)添加到项目中。
- 需要手动创建 QRC 文件。
- 不会创建
_other_files
辅助目标,因此在 Qt Creator 中不会有额外的文件显示。 - 适用于不需要 QML 模块特性的项目,或者需要更细粒度控制资源管理的项目。
总的来说,如果你的项目需要使用 QML 模块并希望简化模块的创建和管理,建议使用 qt_add_qml_module()
。如果你的项目只需要将 QML 文件和其他资源添加到项目中,而不需要使用 QML 模块特性,或者希望有更多的控制权,那么 qt6_add_resources()
是一个更好的选择。
const QUrl url(u"qrc:///Main.qml"_qs);和const QUrl url(QStringLiteral(“qrc:///Main.qml”));的区别
两者之间的主要区别在于字符串字面值的表示方法和编码:
const QUrl url(u"qrc:///Main.qml"_qs);
这里,u
前缀表示该字符串字面值为一个 UTF-16 编码的 Unicode 字符串。字符串后面的_qs
用户自定义字面量(User-defined Literal,UDL),它是 Qt 提供的用于将字符串字面值转换为QString
类型的便捷方法。在这种情况下,字符串字面值是一个 UTF-16 编码的 Unicode 字符串,最终转换为QString
类型。const QUrl url(QStringLiteral("qrc:///Main.qml"));
在这里,QStringLiteral
是一个 Qt 宏,用于在编译时将字符串字面值转换为一个QString
类型的对象。该宏的优势在于避免了在运行时创建QString
对象,从而提高了性能。在这种情况下,字符串字面值是一个普通的字符串,QStringLiteral
将其转换为QString
类型。
在实际使用中,这两种方法都可以实现相同的功能,即创建一个 QUrl
对象来表示资源文件的 URL。只是它们在编译时处理字符串字面值的方式略有不同。考虑到性能和简洁性,推荐使用 QStringLiteral
方法。
qt种qrc查找原理
当您使用 qrc:
前缀引用资源文件时,Qt 会自动查找所有已注册的资源文件。在构建过程中,qt_add_resources()
或 qt6_add_resources()
函数会将资源文件(如 resources.qrc
)编译成二进制文件,并将它们嵌入到最终的可执行文件中。当您在运行时使用 qrc:
前缀引用资源文件时,Qt 会在所有已注册的资源文件中查找匹配的条目。
因此,您不需要在引用资源文件时指定 resources.qrc
,因为 Qt 会自动在所有已注册的资源文件中查找正确的文件。如果您有多个 .qrc
文件,只要确保它们都通过 qt_add_resources()
或 qt6_add_resources()
函数正确注册,Qt 就会在所有已注册的资源文件中查找。
需要注意的是,在使用多个 .qrc
文件时,请确保文件名和路径不会发生冲突,以避免混淆和潜在的错误。
使用无前缀的 URL 引用资源文件
根据 Qt 官方文档,从 Qt 6.2 开始,可以在 QML 代码中省略前缀,但在 C++ 代码中,仍然需要使用 qrc:
前缀来引用资源文件。这是因为 QML 和 C++ 是两种不同的语言,它们有不同的命名规则和语法结构。
在 QML 中,可以使用 import
语句来引用 QML 文件,而不需要使用前缀。但是,在 C++ 中,必须使用 qrc:
前缀来引用资源文件,以便在 QML 中使用。
因此,如果您想在 QML 中使用 C++ 代码,必须在 QML 代码中使用 qrc:
前缀来引用资源文件。如果您只想在 QML 中使用 C++ 代码,则可以省略前缀。