iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >QML与C++交互的实现步骤
  • 767
分享到

QML与C++交互的实现步骤

2024-04-02 19:04:59 767人浏览 八月长安
摘要

目录前言第一个例子:QML中创建c++对象第二个例子:C++中加载QML对象参考前言 文档如是说,QML旨在通过C ++代码轻松扩展。Qt QML模块中的类使QML对象能够从C ++

前言

文档如是说,QML旨在通过C ++代码轻松扩展。Qt QML模块中的类使QML对象能够从C ++加载和操作,QML引擎与Qt元对象系统集成的本质使得C ++功能可以直接从QML调用。这允许开发混合应用程序,这些应用程序是通过混合使用QML,javascript和C ++代码实现的。

QML is designed to be easily extensible through C++ code. The classes in the Qt QML module enable QML objects to be loaded and manipulated from C++, and the nature of QML engine's integration with Qt's meta object system enables C++ functionality to be invoked directly from QML. This allows the development of hybrid applications which are implemented with a mixture of QML, JavaScript and C++ code.

除了从QML访问C ++功能的能力之外,Qt QML模块还提供了从C ++代码执行反向和操作QML对象的方法。

下面会通过示例来讲解QML与C++的交互是如何实现的(内容有点长)。

第一个例子:QML中创建C++对象

文档如是说,使用C ++代码中定义的功能可以轻松扩展QML。由于QML引擎与Qt元对象系统的紧密集成,可以从QML代码访问由QObject派生的类适当公开的任何功能。这使得C ++类的属性和方法可以直接从QML访问,通常很少或无需修改。

QML引擎能够通过元对象系统内省QObject实例。这意味着,任何QML代码都可以访问QObject派生类实例的以下成员:

  • 属性(使用Q_PROPERTY注册的属性)
  • 方法(需注册为public slots或是标记为Q_INVOKABLE)
  • 信号

(此外,如果已使用Q_ENUMS声明枚举,则可以使用枚举。)

通常,无论是否已向QML类型系统注册了QObject派生类,都可以从QML访问它们。但是,如果QML引擎要访问其他类型信息(例如,如果要将类本身用作方法参数或属性,或者要将其中一个枚举类型用于以这种方式使用),那么该类可能需要注册。

代码示例有四个文件,QtQuick Empty工程的两个加自定义的Cpp类h和cpp文件,因为我把几种常用的方法都写出来了,所以看起来有点乱(完整代码链接见文末)。

#ifndef CPPOBJECT_H
#define CPPOBJECT_H
 
#include <QObject>
 
//派生自QObject
//使用qmlReGISterType注册到QML中
class CppObject : public QObject
{
    Q_OBJECT
    //注册属性,使之可以在QML中访问--具体语法百度Q_PROPERTY
    Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(int year READ getYear WRITE setYear NOTIFY yearChanged)
 
public:
    explicit CppObject(QObject *parent = nullptr);
    //通过Q_INVOKABLE宏标记的public函数可以在QML中访问
    Q_INVOKABLE void sendSignal();//功能为发送信号
 
    //给类属性添加访问方法--myName
    void setName(const QString &name);
    QString getName() const;
    //给类属性添加访问方法--myYear
    void setYear(int year);
    int getYear() const;
 
signals:
    //信号可以在QML中访问
    void cppSignalA();//一个无参信号
    void cppSignalB(const QString &str,int value);//一个带参数信号
    void nameChanged(const QString name);
    void yearChanged(int year);
 
public slots:
    //public槽函数可以在QML中访问
    void cppSlotA();//一个无参槽函数
    void cppSlotB(const QString &str,int value);//一个带参数槽函数
 
private:
    //类的属性
    QString myName;
    int myYear;
};
 
#endif // CPPOBJECT_H

在头文件中,我定义了信号和public槽函数,以及Q_INVOKABLE宏标记的public函数,还通过Q_PROPERTY注册了两个属性,这些方法和属性之后都可以在QML中进行访问。

#include "CppObject.h"
 
#include <QDebug>
 
CppObject::CppObject(QObject *parent)
    : QObject(parent),
      myName("none"),
      myYear(0)
{
 
}
 
void CppObject::sendSignal()
{
    //测试用,调用该函数后发送信号
    qDebug()<<"CppObject::sendSignal";
    emit cppSignalA();
    emit cppSignalB(myName,myYear);
}
 
void CppObject::setName(const QString &name)
{
    qDebug()<<"CppObject::setName"<<name;
    if(myName!=name){
        qDebug()<<"emit nameChanged";
        myName=name;
        emit nameChanged(name);
    }
}
 
QString CppObject::getName() const
{
    qDebug()<<"CppObject::getName";
    return myName;
}
 
void CppObject::setYear(int year)
{
    qDebug()<<"CppObject::setYear"<<year;
    if(year!=myYear){
        qDebug()<<"emit yearChanged";
        myYear=year;
        emit yearChanged(myYear);
    }
}
 
int CppObject::getYear() const
{
    qDebug()<<"CppObject::getYear";
    return myYear;
}
 
void CppObject::cppSlotA()
{
    qDebug()<<"CppObject::cppSlotA";
}
 
void CppObject::cppSlotB(const QString &str, int value)
{
    qDebug()<<"CppObject::cppSlotB"<<str<<value;
}

为了测试方便,我给每个函数都加了一个打印语句,当调用sendSignal函数时将会emit两个信号,稍后会在QML中调用该函数。

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "CppObject.h"
 
int main(int arGC, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
 
    QGuiApplication app(argc, argv);
 
    //qmlRegisterType注册C++类型至QML
    //arg1:import时模块名
    //arg2:主版本号
    //arg3:次版本号
    //arg4:QML类型名
    qmlRegisterType<CppObject>("MyCppObject",1,0,"CppObject");
 
    QQmlApplicationEngine engine;
 
    //也可以注册为qml全局对象
    //engine.rootContext()->setContextProperty("cppObj",new CppObject(qApp));
 
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
 
    return app.exec();
}

通过使用qmlRegisterType,将刚才定义的QObject派生类注册到QML中(Qt5.15增加了新的注册方式)。

import QtQuick 2.9
import QtQuick.Window 2.9
//引入我们注册的模块
import MyCppObject 1.0
 
Window {
    id: root
    visible: true
    width: 500
    height: 300
    title: qsTr("QML调用Cpp对象:by 龚建波1992")
    color:"green"
 
    signal qmlSignalA
    signal qmlSignalB(string str,int value)
 
    //鼠标点击区域
    MouseArea{
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton | Qt.RightButton
        //测试时点击左键或右键
        onClicked: {
            if(mouse.button===Qt.LeftButton){
                console.log('----qml 点击左键:Cpp发射信号')
                cpp_obj.name="Gongjianbo"  //修改属性会触发set函数,获取值会触发get函数
                cpp_obj.year=1992
                cpp_obj.sendSignal() //调用Q_INVOKABLE宏标记的函数
            }else{
                console.log('----qml 点击右键:QML发射信号')
                root.qmlSignalA()
                root.qmlSignalB('gongjianbo',1992)
            }
        }
    }
 
    //作为一个QML对象
    CppObject{
        id:cpp_obj
        //也可以像原生QML对象一样操作,增加属性之类的
        property int counts: 0
 
        onYearChanged: {
            counts++
            console.log('qml onYearChanged',counts)
        }
        onCountsChanged: {
            console.log('qml onCountsChanged',counts)
        }
    }
 
    //组件加载完成执行
    Component.onCompleted: {
        //关联信号与信号处理函数的方式同QML中的类型
        //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)
        //Qml对象的信号关联到Cpp
        root.onQmlSignalA.connect(cpp_obj.cppSlotA)
        root.onQmlSignalB.connect(cpp_obj.cppSlotB)
    }
 
    //定义的函数可以作为槽函数
    function processB(str,value){
        console.log('qml function processB',str,value)
    }
}

注册之后就能直接在QML中使用刚才定义的C++类型了,并且可以像QML定义的类型一样进行操作,如信号槽关联、属性绑定等。

这个示例很简单,点击鼠标左键调用CppObj的sendSignal函数来发送信号,QML处理;点击鼠标右键QML发送信号,CppObj处理,下面是操作结果:

可以看到QML成功的访问了CppObj的属性和方法,并能进行信号槽的关联。

第二个例子:C++中加载QML对象

文档如是说,所有QML对象类型都是源自QObject类型,无论它们是由引擎内部实现还是第三方定义。这意味着QML引擎可以使用Qt元对象系统动态实例化任何QML对象类型并检查创建的对象。

这对于从C ++代码创建QML对象非常有用,无论是显示可以直观呈现的QML对象,还是将非可视QML对象数据集成到C ++应用程序中。一旦创建了QML对象,就可以从C ++中检查它,以便读取和写入属性,调用方法和接收信号通知。

可以使用QQmlComponentQQuickView来加载QML文档。QQmlComponent将QML文档作为为一个C++对象加载,然后可以从C++ 代码进行修改。QQuickView也可以这样做,但由于QQuickView是一个基于QWindow的派生类,加载的对象也将可视化显示,QQuickView通常用于将一个可视化的QML对象集成到应用程序的用户界面中。参见文档Qt/Qt5.9.7/Docs/Qt-5.9.7/qtqml/qtqml-cppintegration-interactqmlfromcpp.html

下面通过代码来演示(完整代码链接见文末)。

import QtQuick 2.9
 
Item{
    id: root
    width: 250
    height: 250
    //自定义属性  --cpp可以访问
    property string msg: "GongJianBo1992"
    //自定义信号  --可以触发cpp槽函数
    signal qmlSendMsg(string arg1,string arg2)
 
    Rectangle {
        anchors.fill: parent
        color: "green"
        objectName: "rect" //用于cpp查找对象
    }
 
    MouseArea {
        anchors.fill: parent
        onClicked: {
            console.log("qml 点击鼠标, 发送信号 qmlSendMsg")
            root.qmlSendMsg(root.msg,"myarg2")
        }
    }
 
    onHeightChanged: console.log("qml height changed")
    onWidthChanged: console.log("qml width changed")
 
    //QML中的方法可以被cpp调用,也可以作为槽函数
    function qml_method(val_arg){
        console.log("qml method runing",val_arg,"return ok")
        return "ok"
    }
    //注意槽函数参数为var类型
    function qmlRecvMsg(arg1,arg2){
        console.log("qml slot runing",arg1,arg2)
    }
}

在QML中我定义了一些属性和方法等,用于测试。

#ifndef CPPOBJECT_H
#define CPPOBJECT_H
 
#include <QObject>
#include <QDebug>
 
class CppObject : public QObject
{
    Q_OBJECT
public:
    explicit CppObject(QObject *parent = Q_NULLPTR)
        :QObject(parent){}
 
signals:
    //信号 --用来触发qml的函数
    //注意参数为var类型,对应qml中js函数的参数类型
    void cppSendMsg(const QVariant &arg1,const QVariant &arg2);
 
public slots:
    //槽函数 --用来接收qml的信号
    void cppRecvMsg(const QString &arg1,const QString &arg2){
        qDebug()<<"CppObject::cppRecvMsg"<<arg1<<arg2;
        qDebug()<<"emit cppSendMsg";
        emit cppSendMsg(arg1,arg2);
    }
};
 
#endif // CPPOBJECT_H

Cpp中定义了一个槽函数,用来接收QML对象的信号。 

#include <QGuiApplication>
#include <QQmlProperty>
#include <QQuickView>
#include <QQuickItem>
#include <QMetaObject>
#include <QDebug>
 
#include "CppObject.h"
 
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
 
    QGuiApplication app(argc, argv);
 
    //可以用QQmlComponent\QQuickView\QQuickWidget的C++代码加载QML文档
    //QQuickView不能用Window做根元素
    QQuickView view(QUrl("qrc:/main.qml"));
    view.show();
 
    //获取到qml根对象的指针
    QObject *qmlObj=view.rootObject();
 
    
 
    //【1】
    //通过QObject设置属性值
    qDebug()<<"Cpp set qml property height";
    //qmlObj->setProperty("height",300);
    QQmlProperty(qmlObj,"height").write(300);
    //通过QObject获取属性值
    qDebug()<<"Cpp get qml property height"<<qmlObj->property("height");
    //任何属性都可以通过C++访问
    qDebug()<<"Cpp get qml property msg"<<qmlObj->property("msg");
 
    //【2】
    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();
 
    //【3】
    //通过objectName访问加载的QML对象
    //QObject::findChildren()可用于查找具有匹配objectName属性的子项
    QObject *qmlRect=qmlObj->findChild<QObject*>("rect");
    if(qmlRect){
        qDebug()<<"Cpp get rect color"<<qmlRect->property("color");
    }
 
    //【4】
    //调用QML方法
    QVariant val_return;  //返回值
    QVariant val_arg="GongJianBo";  //参数值
    //Q_RETURN_ARG()和Q_Arg()参数必须制定为QVariant类型
    QMetaObject::invokeMethod(qmlObj,
                              "qml_method",
                              Q_RETURN_ARG(QVariant,val_return),
                              Q_ARG(QVariant,val_arg));
    qDebug()<<"QMetaObject::invokeMethod result"<<val_return; //qml函数中返回“ok”
 
    //【5】
    //关联信号槽
    CppObject cppObj;
    //关联qml信号与cpp槽
    //如果信号参数为QML对象类型,信号用var参数类型,槽用QVariant类型接收
    QObject::connect(qmlObj,SIGNAL(qmlSendMsg(QString,QString)),
                     &cppObj,SLOT(cppRecvMsg(QString,QString)));
    //关联cpp信号与qml槽
    //qml中js函数参数为var类型,信号也用QVariant类型
    QObject::connect(&cppObj,SIGNAL(cppSendMsg(QVariant,QVariant)),
                     qmlObj,SLOT(qmlRecvMsg(QVariant,QVariant)));
    //此外,cpp信号也可以关联qml信号
 
    return app.exec();
}

然后就把文档中的东西测试了下,操作起来很简单。不过相对于QML中使用C++对象来说,感觉作用没那么大,因为一般把QML嵌入到Widgets中才会做这些操作,但是混合两个框架很多坑。下面是我的测试输出结果:

 以上两种方式应该就是最简单的QML与C++交互应用了,对照文档或是博客敲一遍代码可以很容易地理解。

(完结)

代码完整链接(GitHub)如下:

Qml中创建Cpp对象(Cpp注册给Qml):https://GitHub.com/gongjianbo/MyTestCode/tree/master/Qml/QmlCallCpp2020

Cpp中加载Qml对象(Cpp操作Qml):Https://github.com/gongjianbo/MyTestCode/tree/master/Qml/CppCallQml2020

代码的下载链接:QML-C_jb51.rar

参考

文档:Qt/Qt5.9.7/Docs/Qt-5.9.7/qtqml/qtqml-cppintegration-overview.html

文档:Qt/Qt5.9.7/Docs/Qt-5.9.7/qtqml/qtqml-cppintegration-interactqmlfromcpp.html

文档:Qt/Qt5.9.7/Docs/Qt-5.9.7/qtqml/qtqml-cppintegration-topic.html

(注:文档中有很多相关链接,此处忽略)

博客:https://blog.csdn.net/u011012932/column/info/14318

博客:https://blog.csdn.net/baidu_33850454/article/details/81907857

博客:https://blog.csdn.net/baidu_33850454/article/details/81914821

到此这篇关于QML与C++交互的实现步骤的文章就介绍到这了,更多相关QML与C++交互内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: QML与C++交互的实现步骤

本文链接: https://www.lsjlt.com/news/142582.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • QML与C++交互的实现步骤
    目录前言第一个例子:QML中创建C++对象第二个例子:C++中加载QML对象参考前言 文档如是说,QML旨在通过C ++代码轻松扩展。Qt QML模块中的类使QML对象能够从C ++...
    99+
    2024-04-02
  • C++与QML进行数据交互实现方式介绍
    目录一、定义可交互的类二、数据操作类三、注册四、qml调用我所使用的方式,是通过C++调用远端的webservice,再次数据送到qml端,不说原理了,直接上代码的实现过程。需要明白...
    99+
    2024-04-02
  • golang与pgsql交互的实现
    目录1、目的2、代码架构3、代码展示1、目的 通过读取配置文件获取pgsql用户名和密码及数据库和数据表,从而读取所需字段值。 2、代码架构 config/config.go:读取...
    99+
    2023-03-19
    golang pgsql交互 golang pgsql
  • C++与Lua实现交互的原理是什么
    本篇文章给大家分享的是有关C++与Lua实现交互的原理是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。具体步骤:1,找到cocos自带的绑定工具脚本文件genbinding...
    99+
    2023-06-06
  • python 与 C 的交互(ctype
    ctypes是Python的一个外部库,可以使用python语言调用已经编译好的C语言函数以及数据类型并进行数据交换等。ctypes的官方文档在https://docs.python.org/3/library/ctypes....
    99+
    2023-01-31
    python ctype
  • Ajax如何实现异步交互
    这篇文章主要介绍了Ajax如何实现异步交互,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。利用ajax实现异步交互无非4步:1.创建ajax核...
    99+
    2024-04-02
  • 如何让Ajax异步传输与PHP实现交互
    这篇文章主要讲解了“如何让Ajax异步传输与PHP实现交互”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何让Ajax异步传输与PHP实现交互”吧!背景 前台页面两个select框,一个与学...
    99+
    2023-06-08
  • Ajax+js实现异步交互的方法
    小编给大家分享一下Ajax+js实现异步交互的方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!JS是什么JS是JavaScript的简称,它是一种直译式的脚本语...
    99+
    2023-06-08
  • QT与javascript交互数据的实现
    一、数据从QT流向JS 1、QT调用JS的函数,JS通过形参获得QT的值 2、JS调用QT的函数,QT函数的返回值进入JS 二、数据从JS流向QT 1、JS调用QT的函数,QT通过形...
    99+
    2024-04-02
  • Django与数据库交互的实现
    目录1 如何创建项目数据库2 进行数据库与django的交互3 添加数据4 查找数据4 更新数据1 如何创建项目数据库 首先,在虚拟机数据库中建立一个与项目同名的数据库,方便管理。 ...
    99+
    2024-04-02
  • JavaScript与HTML怎么实现交互
    这篇文章主要介绍“JavaScript与HTML怎么实现交互”,在日常操作中,相信很多人在JavaScript与HTML怎么实现交互问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解...
    99+
    2024-04-02
  • PHP与Javascript怎么实现交互
    PHP与Javascript怎么实现交互,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。PHP与Javascript交互的方法:通过Cookie交互。一共是三个文件,分别为:...
    99+
    2023-06-17
  • C#怎么实现允许服务与桌面交互
    本篇内容介绍了“C#怎么实现允许服务与桌面交互”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!onstart的时候修改注册表[HKEY_LOC...
    99+
    2023-06-17
  • golang与pgsql交互如何实现
    本文小编为大家详细介绍“golang与pgsql交互如何实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“golang与pgsql交互如何实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1、目的通过读取配置文...
    99+
    2023-07-05
  • Ajax怎么实现客户端与浏览器异步交互
    今天小编给大家分享一下Ajax怎么实现客户端与浏览器异步交互的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一...
    99+
    2024-04-02
  • 详解c#与python的交互方式
    目录前言: 一、IronPython 二、Python打包exe调用 三、Python提供WebApi接口(推荐) 总结: 前言:  在平时工作中,需求有多种实现方式;根据不同的需...
    99+
    2024-04-02
  • Django与图表的数据交互的实现
    目录环境相关实现思路(需要理解的请结合代码来看)代码:成果展示参考博客在Django开发过程中,遇到了需要图表进行数据可视化的需要。因此查询了相关文档,并记录下如何实现与图表的数据交...
    99+
    2024-04-02
  • Python与数据库的交互怎么实现
    本篇内容介绍了“Python与数据库的交互怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!MongoDB安装模块pip install...
    99+
    2023-06-22
  • PHP底层与操作系统的交互与实现
    PHP底层与操作系统的交互与实现在Web开发中,PHP被广泛应用于服务器端的编程语言,它具有强大的功能和易用性。PHP底层与操作系统的交互与实现是PHP开发者必须掌握的知识之一。本文将介绍PHP底层与操作系统的交互方法,并提供一些具体的代码...
    99+
    2023-11-08
    操作系统 PHP底层 交互实现
  • C#操作DataTable的实现步骤
    目录一、表创建一、表创建二、创建列 -并填充值(添加新数据行) (dt什么都没有、无结构)三、向有结构的dt中添加新数据行四、添加新数据行到dt中的指定位置五、赋值和取值六、筛选行七...
    99+
    2023-05-14
    C#操作DataTable C# DataTable操作
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作