1. 调用方: Cpp, 被调方: Qml
获取qml的组件的属性(qmlProperty)和函数(getQmlText())
Qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Button {
id : btn
property string qmlProperty: "我是QML组件的属性"
text : "测试按钮"
objectName: "btnQml" // 需要设置,qml引擎需要找到
function getQmlText(info) {
return info + " from QML"
}
}
}
Cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QMetaObject>
#include <QDebug>
int main()
{
// ... 省略其他代码
QQmlApplicationEngine engine;
auto qmlObj = engine.rootObjects().first()->findChild<QObject*>("btnQml");
if (qmlObj)
{
QVariant property = qmlObj->property("qmlProperty");
QVariant methodRet;
// Q_RETURN_ARG: qml函数的返回值, Q_ARG: qml函数传入的参数
QMeatObject::invokeMethod(qmlObj, "getQmlText", Qt::AutoConnection,
Qt::AutoConnection, Q_RETURN_ARG(QVariant, methodRet), Q_ARG(QVariant, "test "));
if (methodRet.isValid())
qDebug() << methodRet.toString(); // 输出qml函数的返回值
}
// ... 省略其他代码
}
2. 调用方: Qml, 被调方: Cpp
2.1 两种方法,Qml调用Cpp对象的成员函数
第一种: 使用qmlRegisterSingletonInstance(qml需要导入模块)
Cpp
#pragma once
#include <QObject>
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject* parent = nullptr)
: MyObject(parent) {}
~MyObject() {}
Q_INVOKABLE QString sayHello() // 必须使用Q_INVOKABLE变为元方法
{
return "Hello from Cpp";
}
};
int main()
{
// 省略其他代码...
QQmlApplicationEngine engine;
QScopedPointer<MyObject> example(new MyObject);
/*
参数:
QtQobjectSingleton: qml需要导入的模块名
1: 主版本号
0: 次版本号
MyObj: qml使用的组件名
example.get(): 对象实例
*/
qmlRegisterSingletonInstance("QtQObjectSingleton", 1, 0, "MyObj", example.get());
// 省略其他代码...
}
Qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
// 导入cpp注册的模块
import QtQObjectSingleton 1.0
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
// 使用Cpp
Button {
font.pixelSize: 20
onClicked: {
text = MyObj.sayHello() // 调用Cpp对象的成员函数
}
}
}
第二种: 使用setContextProperty(qml不需要导入模块)
int main()
{
// 省略其他代码...
QQmlApplicationEngine engine;
QScopedPointer<MyObject> example(new MyObject);
engine.rootContext()->setContextProperty("MyObj", example.get());
// 省略其他代码...
}
Qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
//import Qt.example.qobjectSingleton 1.0 // 不需要导入模块名,直接使用
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Button {
id : btn
font.pixelSize: 20
onClicked: {
text = MyObj.sayHello()
}
}
}
2.2 Qml的组件信号和Cpp对象的槽函数绑定
Cpp槽函数的参数如果和qml信号的参数不匹配,需要强转为一致的。但是也有局限,必须能转换成qml支持的类型,qml也就支持以下几种类型
注意: 使用SIGNAL和SLOT宏来进行绑定,否则使用新版本的信号槽绑定会有类型不匹配的错误。
Cpp
#pragma once
#include <QObject>
#include <QDebug>
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject *parent = nullptr)
: QObject(parent) {}
~MyObject() {}
public slots:
void printArg(QString arg)
{
qDebug() << "output arg: " << arg;
}
};
// 省略其他代码...
int main()
{
// 省略其他代码...
QQmlApplicationEngine engine;
MyObject myObj;
auto obj = engine.rootObjects().first()->findChild<QObject*>("btnQml");
if (obj)
{
// 都转换为QString类型,qml的string类型可以直接转换成QString类型
//
QObject::connect(obj, SIGNAL(clickArg(QString)), &myObj, SLOT(printArg(QString)));
}
// 省略其他代码...
}
2.2 Qml处理Cpp的信号
Qml提供了Connections类处理Cpp的信号,前提必须Cpp对象注册到qml引擎中
Cpp
#include <QObject>
class TestObj : public QObject
{
Q_OBJECT
public:
TestObj(QObject* parent = nullptr)
: QObject(parent) {}
~TestObj() {}
// 信号
signals:
void signalFunc();
};
// 省略其他代码...
int main()
{
// 省略其他代码...
QQmlApplicationEngine engine;
TestObj obj;
// 注册到Qml引擎中
engine.rootContext()->setContextProperty("TestObj", &obj);
// 发射TestObj的signalFunc()信号
emit obj.signalFunc();
// 省略其他代码...
}
Qml
// 省略其他代码...
Connections {
target: TestObj // cpp对象注册到qml引擎的名字
// 槽函数
function onSingnalFunc() { // on + cpp的信号名,第一个字母必须大写
console.log("接收到了cpp的信号")
}
}