上一篇介绍了第一种方法:将 C++ 类注册到 QML 环境中, QML 环境中使用该类型创建对象,这篇介绍第二种方法:在 C++ 中构造一个对象,将这个对象设置为 QML 的上下文属性,在 QML 环境中直接使用该属性。
一、注册属性
要将一个 C++ 类注册为属性很简单,CppObject 的 main.cpp 修改后如下:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "CppObject.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
// QML方式:qmlRegisterType注册C++类型至QML
// 参数:qmlRegisterType<C++类型名> (import时模块名 主版本号 次版本号 QML中的类型名)
//qmlRegisterType<CppObject>("MyCppObject", 1, 0, "CppObject");
QQmlApplicationEngine engine;
// 【修改1】C++方式:也可以注册为qml全局对象
engine.rootContext()->setContextProperty("cpp_obj", new CppObject(qApp));
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
注意我在定义 engine 变量后增加的新语句:
engine.rootContext()->setContextProperty("cpp_obj", new CppObject(qApp));
正是这行代码从堆上分配了一个 CppObject 对象,然后注册为 QML 上下文的属性,起了个名字就叫 cpp_obj,为了方便,跟上一篇 QML 文件中定义的对象名保持一致了。
engine.rootContext()
返回的是 QQmlContext 对象。 QQmlContext 类代表一个 QML 上下文,它的setContextProperty()
方法可以为该上下文设置一个全局可见的属性。要注意的是,你 new 出来的对象, QQmlContext 只是使用,不会帮你删除,你需要自己找一个合适的时机来删除它。
二、在 QML 中使用关联到 C++ 对象的属性
一旦调用 setContextProperty() 导出了属性,就可以在 QML 中使用了,不需要 import 语句哦。下面是 main.qml 修改后的代码:
import QtQuick 2.9
import QtQuick.Window 2.9
// 【修改2】引入我们注册的模块
//import MyCppObject 1.0
Window {
id: root
visible: true
width: 500
height: 300
title: qsTr("QML调用Cpp对象")
color: "green"
signal qmlSignalA
signal qmlSignalB(string str, int value)
//定义的函数可以作为槽函数
function processB(str, value){
console.log('qml function processB', str, value)
}
// 鼠标点击区域
MouseArea{
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if(mouse.button === Qt.LeftButton){
console.log('----qml 点击左键:Cpp发射信号')
// 1.修改属性会触发set函数,获取值会触发get函数
cpp_obj.name = "gongjianbo"
cpp_obj.year = 1992
// 2.调用Q_INVOKABLE宏标记的函数
cpp_obj.testFun()
// 3.发射C++信号
cpp_obj.cppSignalA()
cpp_obj.cppSignalB("chenglong", 1995)
}
else{
console.log('----qml 点击右键:QML发射信号')
root.qmlSignalA()
root.qmlSignalB('gongjianbo', 1992)
}
}
}
// 【修改3】作为一个QML对象
// CppObject{
// id: cpp_obj
// //也可以像原生QML对象一样操作,增加属性之类的
// property int counts: 0
// onYearChanged: {
// counts++
// console.log('qml onYearChanged', counts)
// }
// onCountsChanged: {
// console.log('qml onCountsChanged', counts)
// }
// }
// 关联信号与信号处理函数的方式同QML中的类型
Component.onCompleted: {
// 1. Cpp对象的信号关联到Qml的槽函数
// cpp_obj.onCppSignalA.connect(function() {console.log('qml signalA process')})
cpp_obj.onCppSignalA.connect(()=>console.log('qml signalA process')) // js的lambda
cpp_obj.onCppSignalB.connect(processB)
// 2. Qml对象的信号关联到Cpp的槽函数
root.onQmlSignalA.connect(cpp_obj.cppSlotA)
root.onQmlSignalB.connect(cpp_obj.cppSlotB)
}
}
main.qml 代码也就修改了两处,我已经使用方括号标注出来了。效果和功能与上篇一致,这里就不贴效果图和下载链接了,需要可以去上篇查看和下载。
可以看出,导出的属性可以直接使用,与属性关联的对象,它的信号、槽、可调用方法(使用 Q_INVOKABLE 宏修饰的方法)都可以直接使用,但不能通过类名来引用枚举值了。
参考:
《Qt Quick核心编程》第11章
原文链接: https://www.cnblogs.com/linuxAndMcu/p/11962142.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/306750
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!