【C++/QML】C++与QML交互方法(一)

前言

最近开始做新的项目开发,准备采用Qt框架,使用QML作为前端框架,用C++编写底层结构和算法,接触QML时间不长,用此篇文章记录一下C++代码与QML之间的交互方法,以供日后回顾查看与温习。

在我们新创建一个QuickApplication项目之后,我们的项目文件中存在两个初始文件,一个是main.cpp,另一个是main.qml。

图1 main.cpp文件

图2 main.qml文件 

在main.cpp文件中我们可以看到两个不同类型的对象,一个是QGuiApplication类对象,一个是QQmlApplicationEngine类对象,这两个类都是Qt框架中用于处理应用程序生命周期和QML集成的类,但它们在Qt的不同模块中使用,并且有不同的用途和特点。

QGUIApplication 是Qt GUI模块中的一个类,主要用于传统的Qt Widgets应用程序。它继承自 QApplication 类,并添加了一些特定于图形用户界面应用程序的功能。以下是 QGUIApplication 的一些关键特点:

  • 管理应用程序的生命周期,包括初始化和退出。
  • 处理事件循环,响应用户输入和系统事件。
  • 可以与QML集成,但通常用于非QML的Widgets应用程序。

QQmlApplicationEngine 是Qt QML模块中的一个类,专门为QML应用程序设计。它提供了一个用于加载和执行QML代码的高级API。以下是 QQmlApplicationEngine 的一些关键特点:

  • 用于加载和运行QML文件。
  • 支持动态QML内容的加载,可以在运行时加载和卸载QML组件。
  • 提供了与QML集成的高级功能,如JavaScript和C++的绑定。
  • 可以访问QML中的属性和方法,实现QML与C++的双向通信。

QML和C++代码的通讯都是通过Qt Meta-Object System系统实现的,例如信号和槽的连接,属性的获取和修改、C++的槽函数或者被标记为Q_INVOKABLE的方法可以直接被QML调用以及QML可以直接获取Q_ENUM的枚举对象等。

因此QML和C++代码的整合可以通过几种方式实现:

  • 通过上下文属性,利用setContextProperty()方法;
  • 在qml引擎中注册类型,通过在main.cpp中调用qmlRegisterType
  • 使用QML扩展插件

接下来我们来介绍几种C++与QML交互方法

一、SetContextProperty()方法

实现通讯的最重要的一点是:QObjects对象需要被显示地暴露给QML运行时的上下文(QObjects(and value type objects) need to be explicitly exposed to the QML runtime context in order to be accesible),这其中最重要的关键类是QQmlContext

  • 在main.cpp文件的main函数中,我们创建一个QQmlContext对象context,并调用rootContext()指向了engine的根上下文,这个上下文包含了QML代码可以访问的所有初始属性和对象;
  • 调用context的成员函数setContextProperty(),将自定义的属性暴露给context;

  •  之后在main.qml文件中就可以使用qml创建对象,并使用刚才暴露给context的属性“myBackgroundColor"和“myText"的值

void QQmlContext::setContextProperty(const QString &name, QObject *value)方法会传入两个参数,一个是自定义属性的名称,一个是自定义属性的值,这个值是一个QObject*对象,因此常见的类型都可以直接传入。

例如上图所示,你可以将QGuiApplication对象的指针传入,这样就可以在qml中调用相关的函数。

 这个方法会作用于全局,一般来说用到的情况比较少

二、Q_PROPERTY()宏与qmlRegisterSingletonInstance()

上面提到了用setContextObject()方法将属性直接暴露给context,但是这种方式并不安全,也不便于内存管理,因此可以通过qt提供的另一种方法,将C++类暴露给QML进行使用。

首先,我们先创建一个自定义的类MyDataSet用来暴露给QML使用:

 为了让该类与QML进行通讯,我们需要做一下几件事情:

  • 在类中声明Q_OBJECT宏,并继承QObject类,该宏非常重要,是qt框架元对象系统meta-object system的入口,能够让Qt的构建系统知道该类需要元对象编译器(moc:meta-object compiler)进行特殊处理;
  • 使用Q_PROPERTY宏创建需要暴露给QML的属性,该宏需要定义:
    • 属性类型和名称,读取器名称,写入器名称,属性改变通知信号名称。
    • 这其中还有一个特殊的关键字MEMBER,该关键字允许你为该属性设置一个字段,qt会自动生成读写该字段的读取器和写入器,建议不要与READ和WRITE一起使用,因此建议用法如下:
      • READ + WRITE,可读写,自己实现读写器
      • READ,只读,自己实现读取器
      • MEMBER,可读写,指定字段,自动实现读写器

 完成自定义类和Q_PROPERTY的编写之后,我们就可以进行注册:

这里我们使用qmlRegisterSingletonInstance()方法,在qml中注册一个单例对象dataSet, 这样注册有以下的优点:

  1. 集中管理: 单例模式确保了一个类只有一个实例,并提供一个全局访问点。这使得状态和资源可以跨多个组件或对象共享。

  2. 生命周期控制: 单例的生命周期与应用程序的生命周期保持一致,不需要手动创建和销毁,降低了内存泄漏的风险。

  3. QML 访问: 通过注册单例,你可以在 QML 中直接访问该单例的属性和方法,而无需担心对象的创建和销毁。

  4. 类型安全: QML 引擎会在编译时检查单例的使用,确保只有正确的类型被访问,提高了代码的健壮性。

  5. 避免重复实例化: 单例确保了在整个应用程序中只有一个实例,避免了重复创建相同功能的多个实例。

  6. 跨组件共享: 单例可以在不同的组件之间共享,使得状态和行为可以在应用程序的多个部分中保持一致。

  7. 简化 QML 代码: 在 QML 中使用单例,可以避免复杂的对象创建和传递,简化了 QML 代码。

  8. 性能优化: 由于单例是在应用程序启动时创建的,并且持续存在,因此避免了每次需要时都创建新实例的开销。

  9. 更好的封装性: 单例模式隐藏了实现细节,只暴露出一个访问点,使得内部实现可以在不影响使用者的情况下进行更改。

  10. 易于维护和扩展: 当需要添加新功能或修改现有功能时,单例提供了一个清晰的路径来扩展或修改应用程序的行为。

注册完成之后我们就可以在QML中使用我们所注册的对象了:

  • 27
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QMLC++交互方法主要有以下几种: 1. 使用QObject::connect()函数连接QMLC++对象的信号和槽函数,实现数据的传递和交互。 2. 使用Q_INVOKABLE宏将C++函数声明为可在QML中调用的函数。这样,QML可以直接调用C++函数,实现数据的交互。 3. 使用Q_PROPERTY宏将C++对象的属性声明为可在QML中访问的属性。这样,QML可以直接访问C++对象的属性,实现数据的交互。 4. 使用QQmlContext类将C++对象注册到QML中,并在QML中访问这些对象。这样,QML可以直接访问C++对象,实现数据的交互。 下面是一个具体的例子,展示了如何在QML中访问C++对象的属性和函数。 C++代码: ``` // MyObject.h #include <QObject> class MyObject : public QObject { Q_OBJECT Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged) public: explicit MyObject(QObject *parent = nullptr); int value() const; void setValue(int value); signals: void valueChanged(); private: int m_value; }; // MyObject.cpp #include "MyObject.h" MyObject::MyObject(QObject *parent) : QObject(parent) { m_value = 0; } int MyObject::value() const { return m_value; } void MyObject::setValue(int value) { if (m_value != value) { m_value = value; emit valueChanged(); } } ``` QML代码: ``` import QtQuick 2.0 Item { width: 200 height: 200 Text { text: "Value: " + myObject.value } Slider { anchors.top: text.bottom from: 0 to: 100 value: myObject.value onValueChanged: myObject.value = value } Connections { target: myObject onValueChanged: text.text = "Value: " + value } Component.onCompleted: { console.log("Value:", myObject.value) } } ``` 在这个例子中,我们创建了一个名为MyObject的C++对象,并将其注册到QML中。MyObject类有一个名为value的属性和一个名为setValue的槽函数,用于设置属性值。在QML中,我们创建一个Slider和一个Text组件,用于显示和修改MyObject的value属性。我们还使用Connections组件将MyObject的valueChanged信号与Text的text属性绑定,以使其能够自动更新。最后,在Component.onCompleted信号处理程序中,我们打印MyObject的value属性的值,以验证其已成功从C++对象传递到QML界面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值