QML学习笔记【06】:QML与C++交互

本文详细介绍了如何在QML中直接调用C++的成员变量和函数,以及如何实现QML与C++之间的信号槽绑定。首先,需要创建继承自QObject的C++类并使用Q_PROPERTY和Q_INVOKABLE修饰成员,然后通过qmlRegisterType注册模块。在QML端,可以直接操作注册后的C++对象并监听其变化。此外,文中还展示了QML发送信号给C++槽函数以及C++发送信号给QML的方法。
摘要由CSDN通过智能技术生成

1 QML端直接调用C++端变量及函数

1、 创建继承自QObject的C++类,对象必须继承自QObject才能在QML被使用和访问

2、在类定义中使用Q_PROPERTY导出成员的READ、WRITE、NOTIFY接口,这样类中的成员变量就可以在QML调用和修改了,同时变量被修改后也会发送信号通知QML端。用 Q_INVOKABLE 修饰成员函数,这样类中的成员函数就可以直接被QML调用。前提是该模块已经被注册过!!!

class MyObject : public QObject
{
    Q_OBJECT

public:
    explicit MyObject(QObject *parent = nullptr);
    ~MyObject();
    static MyObject * getInstance();

    //读取函数,对应READ
    int getIValue();
    QString getSStr();

    //被 Q_INVOKABLE 修饰C++函数能直接被QML调用
    Q_INVOKABLE void setCapture(bool state);

    //写函数,对应 WRITE,可以没有
    Q_INVOKABLE void setIValue(int value);
    Q_INVOKABLE void setSStr(const QString &str);

    //定义公有的槽函数
public slots:
    Q_INVOKABLE void cppSlot(int i, QString s);

private slots:
    void timer_timeout();

signals:
    //修改通知,对应 NOTIFY,可以没有。可以分开写,也可以用同一个信号
    void iValueChanged(int value);
    void sStrChanged(const QString &str);
    void myObjDataChanged();
    void cppSig(QVariant i, QVariant s);

private:
    QTimer *timer;
    int iValue;
    QString sStr;

    // property declarations required for QML
    Q_PROPERTY(int iValue READ getIValue WRITE setIValue NOTIFY myObjDataChanged)
    Q_PROPERTY(QString sStr READ getSStr WRITE setSStr NOTIFY myObjDataChanged)
};

3、注册模块

QQmlApplicationEngine engine;
//1、使用setContextProperty设置全局对象/上下文对象。作用域为全局
//常用于一些不变的常量
QQmlContext *context = engine.rootContext();
context->setContextProperty("SCREEN_WIDTH", 800);
//2、使用qmlRegisterType注册模块,在qml中通过 import 模块名称 进行引用
//模块名称、主版本号、次版本号、类名称
qmlRegisterType<MyObject>("MyObj11", 1, 0, "MyObject");

4、QML端调用

//创建MyObject对象
MyObject{
    objectName: "myobj"
    //可直接操作MyObject类中的数据了
    id: myobj
    iValue: 10
    sStr: "dhl"
    Component.onCompleted:{
        console.log(iValue, sStr)
    }
}
//监控myobj.iValue的改变
onValueChanged: {
    console.log("onValueChanged: ", value)
}

//1、直接访问C++的成员变量和成员函数....................................
Button{
    id: btn1
    objectName: "button1"
    x:20; y:20
    anchors.margins: 10
    text: "访问C++成员和方法"
    onClicked: {
        myobj.iValue += 2 //修改myobj.iValue的值
        onoff = onoff ? 0 : 1
        myobj.setCapture(onoff) //调用C++端函数
    }
}

2 QML端发送信号绑定C++端槽函数

可有两种方法可绑定QML端信号与C++端槽函数,分别在C++端绑定和在QML端绑定。需要注意的是:方式1实际是在QML信号的槽函数中调用的C++端槽函数,相当于是间接的绑定C++端的槽函数

//2、QML端发送信号绑定C++端槽函数....................................
signal qmlSig(int i, string s)
Button{
    id: btn2
    objectName: "button2"
    x:200; y:20
    anchors.margins: 10
    text: "QML端发送信号绑定C++端"
    onClicked: {
        qmlSig(1, "qml signal--->cpp slot") //发送信号
    }
}
//方式1:在QML中使用Connections连接
//    Connections {
//        target: root
//        onQmlSig:{  //QML信号为 qmlSig(int i, string s)
//            myobj.cppSlot(i, s)
//        }
//    }
//方式2:在QML中使用信号的connect方法
Component.onCompleted: {
    qmlSig.connect(myobj.cppSlot)
}
//方式3:在C++中绑定
//详见 main.cpp

3 C++端发送信号绑定QML端槽函数

可有两种方法可绑定C++端信号与QML端槽函数,分别在C++端绑定和在QML端绑定。需要注意的是:

1、QML中槽函数的参数类型对应c++端的必须都是QVariant!!!!

2、在C++端绑定的方式,经测试,在当前版本中不好使!

//3、C++端发送信号绑定QML端槽函数....................................
function qmlSlot(i, s){ //参数类型对应c++端的必须都是QVariant!!!!
    console.log("qmlslot: ", i, s)
}
//方式1:在QML中使用Connections连接
Connections{
    target: myobj
    onCppSig:{ //c++端信号为void cppSig(QVariant i, QVariant s),C++端发送该信号后,会执行qmlSlot函数
        qmlSlot(i, s)
    }
}
//方式2:在C++中绑定。经测试,此方式在当前版本中不好使!!!
//详见 main.cpp

4 C++端直接调用QML端函数

在C++端需要使用 QMetaObject::invokeMethod 方法来调用QML端函数

//4、C++端直接调用QML端函数....................................
function qmlFunc(i, s){
    return "qmlFunc success"
}
//详见 main.cpp

main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QVariant>
#include <QDebug>
#include "myobject.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    
    //=====》C++与QML数据交互
    //1、使用setContextProperty设置全局对象/上下文对象。作用域为全局
    //常用于一些不变的常量
    QQmlContext *context = engine.rootContext();
    context->setContextProperty("SCREEN_WIDTH", 800);
    //2、使用qmlRegisterType注册模块,在qml中通过 import 模块名称 进行引用
    //模块名称、主版本号、次版本号、类名称
    qmlRegisterType<MyObject>("MyObj11", 1, 0, "MyObject");

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    //=====》C++与QML信号槽绑定
    auto list = engine.rootObjects();
    auto window = list.first();
//    auto buttonObj = list.first()->findChild<QObject *>("button1");
    //绑定qml信号与c++槽
//    QObject::connect(window, SIGNAL(qmlSig(int,QString)),
//                     MyObject::getInstance(), SLOT(cppSlot(int,QString)));
    //绑定c++信号和qml槽
//    QObject::connect(MyObject::getInstance(), SIGNAL(cppSig(QVariant,QVariant)),
//                     window, SLOT(qmlSlot(QVariant, QVariant)));

    //=====》C++直接调用QML函数
    QVariant res;
    QVariant arg1 = 123;
    QVariant arg2 = "dhl";
    QMetaObject::invokeMethod(window, "qmlFunc",
                              Q_RETURN_ARG(QVariant,res),
                              Q_ARG(QVariant, arg1),
                              Q_ARG(QVariant, arg2));
    qDebug() <<"res=" << res;

    return app.exec();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值