交互方式分为四种,qml访问C++,C++调用qml,model/delegate/view机制,使用序列化字符串json,前面两种是基本,后面两个是第一个的特例,如有不严谨的地方,欢迎指正。
qml不能直接访问c++的类型,C++类型必须注册到元对象系统才能被qml访问。qml可以访问属性、信号、槽、枚举定义(Q_ENUM)、函数(Q_INVOKABLE)。
下面以Student类为例,演示上面的各个类型,
第一种方式,注册类型,第一步,定义类型。
#include
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr)
{
}
enum Grade{
FirstGrade,
SecondGrade,
GradeThree
};
Q_ENUM(Grade)
Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChanged)
Q_INVOKABLE void setName(QString value)
{
}
int age()const throw()
{
return m_age;
}
void setAge(int value)
{
if(m_age!=value){
m_age=value;
emit ageChanged();
}
}
signals:
void add(int a,int b);
void ageChanged();
public slots:
void setGrade(Grade value)
{
}
private:
int m_age;
};
qmlRegisterType("csdn.fish", 1, 0, "Student");
第三部,在qml中可以定义该类型,访问age属性,调用setName函数,调用setGrade槽,响应add信号。
import QtQuick.Controls 2.0
import csdn.fish 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Student{
id:liming
age:20
onAdd: console.info(a,b)
onAgeChanged: console.info(age)
Component.onCompleted: {
liming.setName("liming");
liming.setGrade(Student.SecondGrade)
}
}
}
第二种方式是设为context的属性,在main.cpp中这样定义:
#include
#include
#include
#include "Student.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType("csdn.fish", 1, 0, "Student");
QQmlApplicationEngine engine;
Student f_Student;
engine.rootContext()->setContextProperty("superStudent",&f_Student);
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
这样在整个工程的任意qml中可以使用superStudent来访问Student的属性、信号、槽等
import QtQuick 2.7
import QtQuick.Controls 2.0
import csdn.fish 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Student{
id:liming
age:20
onAdd: console.info(a,b)
onAgeChanged: console.info(age)
Component.onCompleted: {
liming.setName("liming");
liming.setGrade(Student.SecondGrade)
}
}
Connections{
target: superStudent
onAgeChanged:{
var i=0
}
}
Component.onCompleted: {
superStudent.setName("hanmeimei")
superStudent.setGrade(Student.FirstGrade)
superStudent.age=15
superStudent.age=16
}
}
首先是main.qml,在qml中定义两个函数,
import QtQuick 2.7
import QtQuick.Controls 2.0
import csdn.fish 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Student{
id:liming
Component.onCompleted: {
liming.setName("liming");
}
function callTeacher(number)
{
console.info(number)
}
function add(a,b)
{
return a+b
}
}
}
c++中通过invokeMethod来调用qml中的函数,可以指定连接方式,如下:
#include
#include
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr)
{
}
Q_INVOKABLE void setName(QString value)
{
QVariant a=QVariant::fromValue(10);
QVariant b=QVariant::fromValue(8);
QVariant retVal;
QMetaObject::invokeMethod(this, "add", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, retVal),
Q_ARG(QVariant, a),
Q_ARG(QVariant, b));
QVariant para=QVariant::fromValue(retVal.toInt());
QMetaObject::invokeMethod(this, "callTeacher", Qt::QueuedConnection,
Q_ARG(QVariant, para));
}
};
这样在调用setName函数中,先直接调用add函数,再调用callteacher函数将加法算出的值(10+8=18)输出到consolve中。
import QtQuick 2.7
import QtQuick.Controls 2.0
import csdn.fish 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Student{
id:liming
Component.onCompleted: {
var test= {
name:"liming",
age:20,
weight:70,
height:180,
sex:"man",
score:[
{
math:95,
english:86
},
{
math:92,
english:81
},
{
math:99,
english:90
}
]
}
var before=JSON.stringify(test,null,4)
liming.setValue(before)
var temp=liming.getValue()
var afterObject=JSON.parse(temp)
var after=JSON.stringify(afterObject,null,4)
console.info("开始:\r\n",before,"\r\n结束:\r\n",after,before==after)
}
}
}
C++中如下:
#include
#include
#include
#include
class Data
{
public:
QString name;
int age;
int weight;
int height;
QString sex;
struct Score{
int math;
int english;
}scores[3];
};
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr)
{
}
Q_INVOKABLE void setValue(QString value)
{
QJsonDocument jsonDocument = QJsonDocument::fromJson(value.toUtf8());
auto root=jsonDocument.object();
data.name=root["name"].toString();
data.age=root["age"].toInt();
data.weight=root["weight"].toInt();
data.height=root["height"].toInt();
data.sex=root["sex"].toString();
QJsonArray score=root["score"].toArray();
for(auto loop=0;loop!=score.size();++loop){
auto source=score[loop].toObject();
auto& dest=data.scores[loop];
dest.math=source["math"].toInt();
dest.english=source["english"].toInt();
}
}
Q_INVOKABLE QString getValue()
{
QJsonObject root;
root["name"]=data.name;
root["age"]=data.age;
root["weight"]=data.weight;
root["height"]=data.height;
root["sex"]=data.sex;
QJsonArray score;
for(auto loop=0;loop!=_countof(data.scores);++loop){
QJsonObject dest;
const auto& source=data.scores[loop];
dest["math"]=source.math;
dest["english"]=source.english;
score.append(dest);
}
root["score"]=score;
QJsonDocument jsonDocument(root);
return jsonDocument.toJson();
}
private:
Data data;
};
输出的结果如下:
qml: 开始:
{
"age": 20,
"height": 180,
"name": "liming",
"score": [
{
"english": 86,
"math": 95
},
{
"english": 81,
"math": 92
},
{
"english": 90,
"math": 99
}
],
"sex": "man",
"weight": 70
}
结束:
{
"age": 20,
"height": 180,
"name": "liming",
"score": [
{
"english": 86,
"math": 95
},
{
"english": 81,
"math": 92
},
{
"english": 90,
"math": 99
}
],
"sex": "man",
"weight": 70
} true