C++与QML交互总结

2023-05-16

一直对于QT的理解和使用都停留在主窗口程序和控制台程序,虽然QT的新东西QML听过也接触过,但是基本上没梳理过调用流程。趁着旧项目要使用QML技术,现在就将C++和QML交互进行总结。

目录

一. QML中使用C++业务类

二.C++使用QML

三.QVariant中方法canConvert和convert使用总结


在C++和QML中均可以定义信号和槽,并且均可以完成信号和槽的绑定

一. QML中使用C++业务类

基本流程如下:

1.将C++注册进入QML引擎,C++类型在qml中当成一个子组件使用

2.在qml中完成信号与槽的绑定

测试代码:

1.QML定义

main.qml

import QtQuick 2.7
import QtQuick.Window 2.2

import WorkClass 1.0

Window {
    id: root
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    signal qmlSignal1
    signal qmlSignal2(string strValue, int iValue)

    MainForm {
        anchors.fill: parent
        mouseArea.onClicked: {
            Qt.quit();
        }
    }

    MouseArea{
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton | Qt.RightButton
        onClicked: {
            if(mouse.button === Qt.LeftButton){
                console.log(' Qt.LeftButton')
                bussiness.strValue = "HelloCpp"
                bussiness.intValue = 2022
                bussiness.sendSignal()
            }else{
                console.log(' Qt.RightButton')
                root.qmlSignal1()
                root.qmlSignal2('hesy', 2000)
            }
        }
    }

    //加载子页面qrcode.qml
    //Loader {
    //    id:accountQRCode
    //    source:"qrcode.qml"
    //    x:(root.width - root.height / 3) / 2
    //    y:root.height / 3
    //    visible: true
    //}

    CBusiness{
        id: bussiness
        property int addpro: 0

        onIntValueChanged: {
            console.log('qml onIntValueChanged', "begin change addpro ", addpro)
            addpro++
            console.log('qml onIntValueChanged', addpro)
        }

        onAddproChanged: {
            console.log('qml onAddFun', addpro)
        }
    }

    Component.onCompleted: {
        bussiness.onSignal1.connect(function(){console.log('no name qml function')})
        bussiness.onSignal2.connect(qmlProcess1)
        root.qmlSignal1.connect(bussiness.slot1)
        root.qmlSignal2.connect(bussiness.slot2)
        console.log('Component.onCompleted')
    }

    function qmlProcess1(str, value){
        console.log('qmlProcess1', str, value)
    }
}

备注:

另外在qml中也可以使用Connections绑定C++业务类函数和qml中的方法,例如 qrcode.qml,其中target:bussiness代表上面的id: bussiness,这样main.qml中包含qrcode.qml,实现了qml之间的调用,以及多个qml和C++之间的调用。

import QtQuick 2.0

Item {
    Image {
        id: qrcode
        sourceSize.width: parent.width
        sourceSize.height: parent.height
        source: ""

    }
    Text {
        id: tips
        x: parent.x
        y: parent.y
        text: qsTr("请扫码")
        font.pixelSize: 24
        visible: false
    }
    Connections {
        target:bussiness
        onAccountQRCodeGenerated: {
            console.log("onAccountQRCodeGenerated invoke !");
            qrcode.source = "image://qrcode/account"
        }
        onAccountScannedSuccess: {
            console.log("onAccountScannedSuccess invoke!");
            qrcode.visible = false
            tips.visible = true
        }
        onAccountLoginSuccess: {
            console.log("onAccountLoginSuccess invoke !");
            tips.text = qsTr("登录成功, 欢迎!")
        }
    }

}

C++中通过发射信号调用qml中方法,对应方法名为on+大写字母开头函数

emit accountQRCodeGenerated();

emit accountScannedSuccess();

emit accountLoginSuccess();

2.C++业务类定义和实现

cbusiness.h

#ifndef CBUSINESS_H
#define CBUSINESS_H

#include <QObject>

class CBusiness : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString strValue READ getStrValue WRITE setStrValue NOTIFY strValueChanged)
    Q_PROPERTY(int intValue READ getIntValue WRITE setIntValue NOTIFY intValueChanged)

public:
    explicit CBusiness(QObject *parent = 0);
    Q_INVOKABLE void sendSignal();

    void setStrValue(QString strValue);
    QString getStrValue() const;
    void setIntValue(int intValue);
    int getIntValue() const;

signals:
    void signal1();
    void signal2(QString strValue, int intValue);
    void strValueChanged(QString strValue);
    void intValueChanged(int intValue);

public slots:
    void slot1();
    void slot2(QString strValue, int intValue);

private:
    //类的属性
    QString m_strValue;
    int m_intValue;
};

#endif // CBUSINESS_H

cbusiness.cpp

#include "cbusiness.h"
#include <QDebug>

CBusiness::CBusiness(QObject *parent) : QObject(parent), m_strValue(""), m_intValue(0)
{
}


void CBusiness::sendSignal()
{
    qDebug() << "CBusiness::" << __FUNCTION__;
    emit signal1();
    emit signal2(m_strValue, m_intValue);
}

void CBusiness::setStrValue(QString strValue)
{
    qDebug() << "CBusiness::" << __FUNCTION__ << strValue;
    m_strValue = strValue;
    emit strValueChanged(strValue);
    qDebug()<< "CBusiness::" << "emit strValueChanged" << endl;
}

QString CBusiness::getStrValue() const
{
    qDebug() << "CBusiness::" << __FUNCTION__;
    return m_strValue;
}

void CBusiness::setIntValue(int intValue)
{
    qDebug() << "CBusiness::" << __FUNCTION__;
    m_intValue = intValue;
    emit intValueChanged(intValue);
    qDebug()<< "CBusiness::" << "emit intValueChanged";
}


int CBusiness::getIntValue() const
{
    qDebug() << "CBusiness::" << __FUNCTION__;
    return m_intValue;
}

void CBusiness::slot1()
{
    qDebug() << "CBusiness::" << __FUNCTION__;
}

void CBusiness::slot2(QString strValue, int intValue)
{
    qDebug() << "CBusiness::" << __FUNCTION__;
    qDebug() << "CBusiness:: " << strValue << "  " << intValue;
}

3.主调函数

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include "cbusiness.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    //qmlRegisterType注册C++类型至QML
    //arg1:import时模块名
    //arg2:主版本号
    //arg3:次版本号
    //arg4:QML类型名
    qmlRegisterType<CBusiness>("WorkClass", 1, 0, "CBusiness");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

4.测试结果

鼠标左键点击:

 说明:

信号和槽的绑定在qml中完成,鼠标左键按下,首先打印:qml: Qt.LeftButton

bussiness.strValue = "HelloCpp" 触发 CBusiness::setStrValue(

因为如下:


Q_PROPERTY(QString strValue READ getStrValue WRITE setStrValue NOTIFY strValueChanged)  

此处= "HelloCpp" 其实是调用的setStrValue

)调用

bussiness.intValue = 2022触发CBusiness::setIntValue(


因为如下:
Q_PROPERTY(int intValue READ getIntValue WRITE setIntValue NOTIFY intValueChanged)  

此处= 2022其实是调用的setIntValue

)调用, 然后调用emit strValueChanged(strValue);,触发qml中 onIntValueChanged调用,接着addpro++触发onAddproChanged调用

最后调用CBusiness::sendSignal(),触发emit signal1(); emit signal2(m_strValue, m_intValue);信号,调用qml的槽 


function(){console.log('no name qml function')

function qmlProcess1(str, value)

鼠标右键点击:

 说明:

鼠标右键,通过qml信号调用到c++的槽函数,并且还传递参数给c++

二.C++使用QML

基本流程如下:

1.在C++中获得qml对象指针

2.在C++中完成信号和槽的绑定

测试代码:

1.QML定义

main.qml

import QtQuick 2.7
import QtQuick.Window 2.2

Item {
    id: root
    visible: true
    width: 640
    height: 480
    //title: qsTr("Hello World")

    property string msg: "I am QML Item"
    signal callCpp(string arg1, string arg2)

    MainForm {
        anchors.fill: parent
        mouseArea.onClicked: {
            Qt.quit();
        }
    }

    Rectangle {
        anchors.fill: parent
        color: "blue"
        objectName: "rect"
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            console.log("onClicked, callCpp")
            root.callCpp(root.msg, "notify cpp")
        }
    }

    onHeightChanged: {
        console.log("onHeightChanged execute")
    }
    onWidthChanged: {
        console.log("onWidthChanged execute")
    }


    //QML中的方法可以被cpp调用,也可以作为槽函数
    function qmlFun(val_arg) {
        console.log("qmlFun execute", val_arg, "return qmlFun_return_result")
        return "qmlFun_return_result"
    }
    //注意槽函数参数为var类型
    function invokeFromCpp(arg1, arg2) {
        console.log("invokeFromCpp execute ", arg1, arg2)
    }
}

2.C++业务类定义和实现

cbusiness.h

#ifndef CBUSINESS_H
#define CBUSINESS_H

#include <QObject>

class CBusiness : public QObject
{
    Q_OBJECT
public:
    explicit CBusiness(QObject *parent = 0);

signals:
    void callQml(const QVariant &arg1,const QVariant &arg2);

public slots:
    void invokeFromQml(const QString &arg1,const QString &arg2);
};

#endif // CBUSINESS_H

cbusiness.cpp

#include "cbusiness.h"

#include <QDebug>

CBusiness::CBusiness(QObject *parent) : QObject(parent)
{

}

void CBusiness::invokeFromQml(const QString &arg1,const QString &arg2)
{
    qDebug() << "CBusiness::" << __FUNCTION__ << arg1 << arg2;
    qDebug() << "CBusiness::" << __FUNCTION__ << " emit callQml";
    emit callQml("I am cpp", "notify qml");
}

3.主调函数

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlProperty>
#include <QQuickView>
#include <QQuickItem>
#include <QMetaObject>
#include <QDebug>

#include "cbusiness.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    /*
    可以用QQmlComponent\QQuickView\QQuickWidget的C++代码加载QML文档
    当使用QQuickView时,qml的根不能是Window
    */
    QQuickView view(QUrl("qrc:/main.qml"));
    view.show();

    // 获取到qml根对象的指针
    QObject *qmlObj = view.rootObject();


        /*
        修改qml属性值的方法
        QObject::setProperty()  QQmlProperty  QMetaProperty::write()
        */

    // 通过QObject设置属性值
    qDebug() << "cpp: " << "set qml property height";
    QQmlProperty(qmlObj, "height").write(500);  //qmlObj->setProperty("height",500);
    // 通过QObject获取属性值
    qDebug() << "cpp: " << "get qml property height" << qmlObj->property("height").toDouble();
    // C++访问qml的其它属性
    qDebug() << "cpp: " << "get qml property msg" << qmlObj->property("msg").toString();


    // 获取QQuickItem
    QQuickItem *item = qobject_cast<QQuickItem*>(qmlObj);
    // 通过QQuickItem设置属性值
    qDebug() << "cpp: " << "set qml property width";
    item->setWidth(300);
    // 通过QQuickItem获取属性值
    qDebug() << "cpp: " << "get qml property width" << item->width();


    // 通过object name访问加载的QML对象
    // QObject::findChildren()可用于查找具有匹配object name属性的子项
    QObject *qmlRect = qmlObj->findChild<QObject*>("rect");
    if(qmlRect)
    {
        qDebug() << "cpp: " << "get rect color" << qmlRect->property("color");
    }


    // C++调用QML方法
    QVariant valReturn;
    QVariant valArg = "I am cpp";
    //Q_RETURN_ARG()和Q_Arg()参数必须制定为QVariant类型
    QMetaObject::invokeMethod(qmlObj, "qmlFun",
                              Q_RETURN_ARG(QVariant,valReturn),
                              Q_ARG(QVariant,valArg));
    qDebug() << "cpp: " << "QMetaObject::invokeMethod result" << valReturn.toString(); //qml函数中返回“ok”


    CBusiness cppObj;
    // cpp和qml信号与槽关联
    // qml信号绑订cpp的槽,用QString类型
    QObject::connect(qmlObj, SIGNAL(callCpp(QString, QString)), &cppObj, SLOT(invokeFromQml(QString, QString)));

    //关联cpp信号与qml槽
    // cpp的信号绑定qml槽,用QVariant类型
    QObject::connect(&cppObj, SIGNAL(callQml(QVariant, QVariant)), qmlObj, SLOT(invokeFromCpp(QVariant, QVariant)));

    return app.exec();
}

4.测试结果

信号和槽的绑定在c++代码中完成,在c++中可以修改qml的属性,获取qml的属性,调用qml的方法,传递和获取参数均可以

 鼠标点击

 鼠标点击后,通过qml的信号callCpp调用c++的槽函数invokeFromQml,然后再通过c++的信号函数callQml调用qml的槽函数invokeFromCpp

三.QVariant中方法canConvert和convert使用总结

1.canConvert只是报告QVariant进行两个类型之间转换的能力,例如QString和Int类型之间的转换,关注类型
2.convert判断的是QVariant进行两个类型的数据之间转换的能力,例如“123”和123之间的转换,关注数据

举例:

QString str1 = "Qt5.7.0";
QVariant var1 = str1;

qDebug() << var1.canConvert(QVariant::Int); // true
qDebug() << var1.convert(QVariant::Int); // false
qDebug() << var1.toString(); // "0"

var1 = str1;
qDebug() << var1.convert(QVariant::String); // true
qDebug() << var1.toString(); // "Qt5.7.0"

QString str2 = "789";
QVariant var2 = str2;

qDebug() << var2.canConvert(QVariant::Int); // true
qDebug() << var2.convert(QVariant::Int); // true
qDebug() << var2.toString(); // "789"

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++与QML交互总结 的相关文章

随机推荐

热门标签