如何集成QML与C++?
如何集成QML与C++?
Qt,QML,Qt Quick本文是关于如何向Qml暴露C++ 对象和注册C++ 类 这一系列教程的第一篇文章。这一系列的教程名字就叫“ 如何集成C++ 和Qml ”。在Qt软件开发中,使用Qt 6这一新版本来恰当和轻松地实现这一关键机制,还不够清晰。特别是有不少朋友正从qmake转为CMake。因此,我们认为这恰好是个好机会,来说清楚Qml和C++ 集成的各种方式的细节。
接下来的博文会涵盖诸如模型和插件,但现在我们先聚焦于基础一些的,来说清楚如何从qml访问C++ 对象和如何向qml注册C++ 类。
在完善语法格式后的类AppManager
看起来象这样:
- #ifndef APPMANAGER_H
- #define APPMANAGER_H
- #include
- class AppManager : public QObject
- {
- Q_OBJECT
- Q_PROPERTY(bool isNightMode READ isNightMode WRITE setIsNightMode NOTIFY isNightModeChanged)
- public:
- explicit AppManager(QObject *parent = nullptr);
- bool isNightMode() const;
- void setIsNightMode(bool isNightMode);
- signals:
- void isNightModeChanged();
- private:
- bool m_isNightMode = false;
- };
- #endif // APPMANAGER_H
在main.cpp
文件(或其它可以访问Qml 引擎的地方)实例化类对象,并使用引擎顶级上下文的方法:QQmlContext::setContextProperty(const QString &name, QObject *value) 来将其暴露。需要为方法传入即将暴露给Qml的可访问的对象名,以及指向该对象的指针。main.cpp
大概是这个样子:
- #include
- #include
- #include
- #include
- int main(int argc, char *argv[])
- {
- QGuiApplication app(argc, argv);
- QQmlApplicationEngine engine;
- // exposing C++ object to Qml
- AppManager *appManager = new AppManager(&app);
- engine.rootContext()->setContextProperty("appManager", appManager);
- const QUrl url(u"qrc:/testapp/main.qml"_qs);
- 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();
- }
大概就这样。你所需要做的就是调用setContextProperty() 方法。这样,就可以从Qml中访问C++ 对象了。 本例中,还会写一个简单的Qml 代码来根据appManager 的isNightMode属性值来更改应用的主题。应用会有一个按钮,以允许用户来更改属性值。
- import QtQuick
- import QtQuick.Controls
- Window {
- id: root
- readonly property color darkColor: "#218165"
- readonly property color lightColor: "#EBEBEB"
- width: 280
- height: 150
- visible: true
- title: qsTr("Expose C++ object test")
- color: root.lightColor
- Column {
- anchors.centerIn: parent
- spacing: 20
- Text {
- id: resultText
- color: root.darkColor
- }
- Button {
- anchors.horizontalCenter: parent.horizontalCenter
- text: qsTr("Start operation")
- palette.buttonText: root.darkColor
- onClicked: {
- appManager.performOperation()
- }
- }
- }
- Connections {
- target: appManager
- function onOperationFinished(result) {
- resultText.text = "Operation result: " + result
- }
- }
- }
如你所见,C++ 对象的属性既可读又可写。因为宏Q_PROPERTY里的isNightModeChanged() 信号,文本内容及其颜色会自动调整。当程序运行时,效果如下:
CMakeLists.txt
文件中会被用到,它看上去是这样:
- qt_add_qml_module(testapp
- URI testapp
- VERSION 1.0
- QML_FILES main.qml
- )
为了向Qml注册C++ 类,需要通过这个CMake方法,指定添加到Qml模块的C++ 源文件列表。向下面的例子这样设置SOURCES
参数。
- qt_add_qml_module(testapp
- URI testapp
- VERSION 1.0
- QML_FILES main.qml
- SOURCES AppManager.h AppManager.cpp
- )
在Qml文件中导入模块后,就可以象实例化其它Qml类型那样实例化AppManager类了。
- import QtQuick
- import QtQuick.Controls
- import testapp // own module
- Window {
- id: root
- readonly property color darkColor: "#218165"
- readonly property color lightColor: "#EBEBEB"
- width: 280
- height: 150
- visible: true
- title: qsTr("Expose C++ object test")
- color: appManager.isNightMode ? root.darkColor : root.lightColor
- Column {
- anchors.centerIn: parent
- spacing: 20
- Text {
- color: appManager.isNightMode ? root.lightColor : root.darkColor
- text: qsTr("Is night mode on? - ") + appManager.isNightMode
- }
- Button {
- anchors.horizontalCenter: parent.horizontalCenter
- text: qsTr("Change mode")
- palette.buttonText: appManager.isNightMode ? root.lightColor : root.darkColor
- // change isNightMode on clicked
- onClicked: {
- appManager.isNightMode = !appManager.isNightMode
- }
- }
- }
- AppManager {
- id: appManager
- }
- }