【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章

原文链接: https://www.cnblogs.com/linuxAndMcu/p/11962142.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    【QML与C++混合编程】在 QML 中使用 C++ 类和对象(二)

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/306750

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月16日 上午4:40
下一篇 2023年2月16日 上午4:41

相关推荐