C++与QML交互,实际项目中采用的是QML和js开发界面,C++实现功能逻辑,故C++与QML交互大多是QML调用C++,交互内容主要有QML调C++接口、QML接收C++的信号、QML使用C++对象的属性等。QML要调用C++必须基于元对象系统,C++类需要继承自QObject,可以通过注册到QML类型系统中使用,也可以直接暴露C++对象给QML进行使用
注册c++类型
C++类可以注册为可实例化的QML类型,这样它就可以像QML代码中的任何普通QML对象类型一样被实例化和使用
1、qmlRegisterType
qmlRegisterType<TestManager>("TestManager", 1, 0, "TestManager");
import TestManager 1.0
2、宏QML_ELEMENT
该方式是通过构建系统进行注册,如果有多个对象需要注册,这种方式还是比较简便的
class Slider : public QObject
{
Q_OBJECT
QML_ELEMENT
...
}
在pro文件中定义名称及版本
CONFIG += qmltypes
QML_IMPORT_NAME = com.mycompany.qmlcomponents
QML_IMPORT_MAJOR_VERSION = 1
调用方式和上面的一样
import com.mycompany.qmlcomponents 1.0
Slider {
// ...
}
QML使用的名称默认和类名一致,若要另外指定名称,则可以使用QML_NAMED_ELEMENT
3、单例属性qmlRegisterSingletonInstance
这种方式我也没用过,就不展开了
暴露C++对象
使用QML引擎添加c++对象为上下文属性
TestManager manager;
engine.rootContext()->setContextProperty("manager", &manager);
manager在QML中将作为全局对象使用
Rectangle {
width: 100
height: 100
color: manager.color
}
交互方式
接口调用
使用Q_INVOKABLE对接口函数进行声明,该宏的作用是允许通过元对象系统进行调用
Q_INVOKABLE void add(int a, int b);
或者是public slots:
public slots:
void add2(int a, int b);
接收信号
从QML代码可以访问任何从QObject派生的类型的公共信号
signals:
void sendAdd(int val);
QML绑定接收,函数名称使用on+信号名称,信号名称需大写
Connections {
target: manager
function onSendAdd(val) {
console.log("add value" + val)
}
}
属性
使用Q_PROPERTY添加属性
Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged)
QML调用
Manager {
id: manager
color: "red"
}
具体可参考我的令一篇文章关于属性的使用
交互的方式还有枚举类型,目前在项目中用得不多,就不做记录了
C++与QML数据类型转换
当数据值在QML和C++之间交换时,它们被QML引擎转换成适合在QML或C++中使用的正确数据类型。这要求交换的数据是引擎可识别的类型。
QML引擎为大量Qt C++数据类型提供了内置支持。
基本的数据类型有
Qt Type | QML Basic Type |
bool | bool |
unsigned int, int | int |
double | double |
float, qreal | real |
QString | string |
QUrl | url |
QColor | color |
QFont | font |
QDateTime | date |
QPoint, QPointF | point |
QSize, QSizeF | size |
QRect, QRectF | rect |
QMatrix4x4 | matrix4x4 |
QQuaternion | quaternion |
QVector2D, QVector3D, QVector4D | vector2d, vector3d, vector4d |
Enums declared with Q_ENUM() or Q_ENUMS() | enumeration |
数据所有权
当数据从C++转移到QML时,数据的所有权总是属于C++。此规则的例外情况是当从显式C++方法调用返回QObject时:在这种情况下,QML引擎会假定对象的所有权,除非通过调用指定了qqmlengine::CppOwnership的qqmlengine::setObjectOwnership()已将对象的所有权显式设置为保留在C++中。
此外,QML引擎尊重Qt C++对象的正常QObject父所有权语义,并且永远不会删除具有父对象的QObject实例。
这一点很关键,很多时候会出现c++释放了相关的数据,QML界面又进行释放,就会出现崩溃的情况,不清楚的就出现莫名其妙的崩溃,QML又和c++不一样,这种情况实属不好定位
结语
关于C++与QML交互的内容其实是挺多,这里只介绍常见的用法和注意点,想要了解更多可以看看官方文档
- 暴露c++对象 https://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html
- 注册c++类型 https://doc.qt.io/qt-5/qtqml-cppintegration-definetypes.html#registering-c-types-with-the-qml-type-system
- c++与QML数据转换 https://doc.qt.io/qt-5/qtqml-cppintegration-data.html
本文章介绍的demo地址