QML/C++混合编程

前言

QML和C++混合编程的好处在于,分离前端UI和后台业务。而且C++在处理效率上也会比QML和JS更加快,并且C++的编写后台业务也有更多的库可供选择。

C++类

代码如下,万事先开代码:

robject.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef ROBJECT_H
#define ROBJECT_H

#include <QObject>
#include <QColor>
class RObject : public QObject
{
Q_OBJECT
//导出属性 可读,可写,通知
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
public:
explicit RObject(QObject *parent = nullptr);
//导出方法
Q_INVOKABLE void print(QString str);


QColor color();
void setColor(QColor color);
signals:
void colorChanged();

public slots:
int add(int a,int b);

private:
QColor m_color;
};

#endif // ROBJECT_H

robject.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "robject.h"
#include <QDebug>
RObject::RObject(QObject *parent) : QObject(parent)
{

}

void RObject::print(QString str)
{
qDebug()<<str;
}

QColor RObject::color()
{
return m_color;
}

void RObject::setColor(QColor color)
{
m_color=color;
emit colorChanged();
}

int RObject::add(int a, int b)
{
return a+b;
}

首先想要把一个c++类注册到QML中,需要这个类继承QObject,这是Qt的基石,元对象系统。QML可以访问RObject类中如下部分:

  1. 通过Q_PROPERTY定义的属性

  2. 通过Q_INVOKABLE导出的函数(不是槽函数)

  3. 槽函数

  4. 信号

QML调用C++类

使用方法有两种

注册类

将C++类注册成QML中一个Component。使用如下:

1
2
3
4
QQmlApplicationEngine engine;
qmlRegisterType<RObject>("Gdwy.Robject", 1, 0, "RObject");

engine.load(QUrl(QLatin1String("qrc:/main.qml")));

注意注册类型必须在加载qml文件之前,不然qml里面import的包就无法识别了。qmlRegisterType是一个模板函数,<>里面是需要注册的类名,第一个参数是注册的包名,类似于QtQuick,这个包名的好处在于我们可以将多个类按照不同的模块导出到不同的包名里面进行管理。第二个参数是大版本号,第三个参数是小版本号,第四个参数是导出到QML里面使用的component名。对应的QML使用如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
RObject{

id:robejct
color: Qt.rgba(255,0,0,0)
}
MouseArea{
anchors.fill: parent
onClicked: {
console.log(robejct.color);
robejct.color=Qt.rgba(0,255,0,0);
var result=robejct.add(1,2);
robejct.print("测试");
console.log(result);

}
}

Connections{
target: robejct
onColorChanged:{
console.log(robejct.color);
}
}

此处连接RObject的colorChanged()信号时,要写成onColorChanged,不然无法识别该信号。

注册属性

1
2
3
4
5
6
7
8
9
10
11
12
13
QQmlApplicationEngine engine;

engine.load(QUrl(QLatin1String("qrc:/main.qml")));

if (engine.rootObjects().isEmpty())
return -1;
else{

QScopedPointer<RObject> object(new RObject);

engine.rootContext()->setContextProperty("robject",object.data());

}

这是将一个RObject的实例注册为main.qml根元素的一个属性。此处采用智能指针是因为qml不会帮助这个实例释放,所以采取智能指针自动释放。QMl的用法就当做普通的属性使用即可。这里使用C++仅仅只是传递了一个简单的数据类型int,转换到js之后会自动转换为js的int类型。但是如果你想传递一个数组类型,可以使用QVariantList,QVariant又是一个模板类,可以包含任何数据类型,包括map,QObject,int等等。QVariantList传递到js里面之后会转换成js的数组(array)类型,这时候遍历解析也要使用js的方法,记住此时数据已经是一个js的对象,不能再使用原来的c++的方法,要转换这个思维。


QML/C++混合编程
http://yoursite.com/2019/04/28/QML-CPP混合编程/
作者
还在输入
发布于
2019年4月28日
许可协议