【QML与C++混合编程】在 QML 中使用 C++ 类和对象(二)
上一篇介绍了第一种方法:将 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章
分类:
Qt / Qt Quick学习
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探