欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

QML與C++交互的實(shí)現(xiàn)步驟

 更新時(shí)間:2022年03月15日 15:35:34   作者:龔建波  
本文主要介紹了QML與C++交互的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

前言

文檔如是說,QML旨在通過C ++代碼輕松擴(kuò)展。Qt QML模塊中的類使QML對(duì)象能夠從C ++加載和操作,QML引擎與Qt元對(duì)象系統(tǒng)集成的本質(zhì)使得C ++功能可以直接從QML調(diào)用。這允許開發(fā)混合應(yīng)用程序,這些應(yīng)用程序是通過混合使用QML,JavaScript和C ++代碼實(shí)現(xiàn)的。

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 ++代碼執(zhí)行反向和操作QML對(duì)象的方法。

下面會(huì)通過示例來講解QML與C++的交互是如何實(shí)現(xiàn)的(內(nèi)容有點(diǎn)長)。

第一個(gè)例子:QML中創(chuàng)建C++對(duì)象

文檔如是說,使用C ++代碼中定義的功能可以輕松擴(kuò)展QML。由于QML引擎與Qt元對(duì)象系統(tǒng)的緊密集成,可以從QML代碼訪問由QObject派生的類適當(dāng)公開的任何功能。這使得C ++類的屬性和方法可以直接從QML訪問,通常很少或無需修改。

QML引擎能夠通過元對(duì)象系統(tǒng)內(nèi)省QObject實(shí)例。這意味著,任何QML代碼都可以訪問QObject派生類實(shí)例的以下成員:

  • 屬性(使用Q_PROPERTY注冊(cè)的屬性)
  • 方法(需注冊(cè)為public slots或是標(biāo)記為Q_INVOKABLE)
  • 信號(hào)

(此外,如果已使用Q_ENUMS聲明枚舉,則可以使用枚舉。)

通常,無論是否已向QML類型系統(tǒng)注冊(cè)了QObject派生類,都可以從QML訪問它們。但是,如果QML引擎要訪問其他類型信息(例如,如果要將類本身用作方法參數(shù)或?qū)傩?,或者要將其中一個(gè)枚舉類型用于以這種方式使用),那么該類可能需要注冊(cè)。

代碼示例有四個(gè)文件,QtQuick Empty工程的兩個(gè)加自定義的Cpp類h和cpp文件,因?yàn)槲野褞追N常用的方法都寫出來了,所以看起來有點(diǎn)亂(完整代碼鏈接見文末)。

#ifndef CPPOBJECT_H
#define CPPOBJECT_H
 
#include <QObject>
 
//派生自QObject
//使用qmlRegisterType注冊(cè)到QML中
class CppObject : public QObject
{
    Q_OBJECT
    //注冊(cè)屬性,使之可以在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宏標(biāo)記的public函數(shù)可以在QML中訪問
    Q_INVOKABLE void sendSignal();//功能為發(fā)送信號(hào)
 
    //給類屬性添加訪問方法--myName
    void setName(const QString &name);
    QString getName() const;
    //給類屬性添加訪問方法--myYear
    void setYear(int year);
    int getYear() const;
 
signals:
    //信號(hào)可以在QML中訪問
    void cppSignalA();//一個(gè)無參信號(hào)
    void cppSignalB(const QString &str,int value);//一個(gè)帶參數(shù)信號(hào)
    void nameChanged(const QString name);
    void yearChanged(int year);
 
public slots:
    //public槽函數(shù)可以在QML中訪問
    void cppSlotA();//一個(gè)無參槽函數(shù)
    void cppSlotB(const QString &str,int value);//一個(gè)帶參數(shù)槽函數(shù)
 
private:
    //類的屬性
    QString myName;
    int myYear;
};
 
#endif // CPPOBJECT_H

在頭文件中,我定義了信號(hào)和public槽函數(shù),以及Q_INVOKABLE宏標(biāo)記的public函數(shù),還通過Q_PROPERTY注冊(cè)了兩個(gè)屬性,這些方法和屬性之后都可以在QML中進(jìn)行訪問。

#include "CppObject.h"
 
#include <QDebug>
 
CppObject::CppObject(QObject *parent)
    : QObject(parent),
      myName("none"),
      myYear(0)
{
 
}
 
void CppObject::sendSignal()
{
    //測(cè)試用,調(diào)用該函數(shù)后發(fā)送信號(hào)
    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;
}

為了測(cè)試方便,我給每個(gè)函數(shù)都加了一個(gè)打印語句,當(dāng)調(diào)用sendSignal函數(shù)時(shí)將會(huì)emit兩個(gè)信號(hào),稍后會(huì)在QML中調(diào)用該函數(shù)。

#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è)C++類型至QML
    //arg1:import時(shí)模塊名
    //arg2:主版本號(hào)
    //arg3:次版本號(hào)
    //arg4:QML類型名
    qmlRegisterType<CppObject>("MyCppObject",1,0,"CppObject");
 
    QQmlApplicationEngine engine;
 
    //也可以注冊(cè)為qml全局對(duì)象
    //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派生類注冊(cè)到QML中(Qt5.15增加了新的注冊(cè)方式)。

import QtQuick 2.9
import QtQuick.Window 2.9
//引入我們注冊(cè)的模塊
import MyCppObject 1.0
 
Window {
    id: root
    visible: true
    width: 500
    height: 300
    title: qsTr("QML調(diào)用Cpp對(duì)象:by 龔建波1992")
    color:"green"
 
    signal qmlSignalA
    signal qmlSignalB(string str,int value)
 
    //鼠標(biāo)點(diǎn)擊區(qū)域
    MouseArea{
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton | Qt.RightButton
        //測(cè)試時(shí)點(diǎn)擊左鍵或右鍵
        onClicked: {
            if(mouse.button===Qt.LeftButton){
                console.log('----qml 點(diǎn)擊左鍵:Cpp發(fā)射信號(hào)')
                cpp_obj.name="gongjianbo"  //修改屬性會(huì)觸發(fā)set函數(shù),獲取值會(huì)觸發(fā)get函數(shù)
                cpp_obj.year=1992
                cpp_obj.sendSignal() //調(diào)用Q_INVOKABLE宏標(biāo)記的函數(shù)
            }else{
                console.log('----qml 點(diǎn)擊右鍵:QML發(fā)射信號(hào)')
                root.qmlSignalA()
                root.qmlSignalB('gongjianbo',1992)
            }
        }
    }
 
    //作為一個(gè)QML對(duì)象
    CppObject{
        id:cpp_obj
        //也可以像原生QML對(duì)象一樣操作,增加屬性之類的
        property int counts: 0
 
        onYearChanged: {
            counts++
            console.log('qml onYearChanged',counts)
        }
        onCountsChanged: {
            console.log('qml onCountsChanged',counts)
        }
    }
 
    //組件加載完成執(zhí)行
    Component.onCompleted: {
        //關(guān)聯(lián)信號(hào)與信號(hào)處理函數(shù)的方式同QML中的類型
        //Cpp對(duì)象的信號(hào)關(guān)聯(lián)到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對(duì)象的信號(hào)關(guān)聯(lián)到Cpp
        root.onQmlSignalA.connect(cpp_obj.cppSlotA)
        root.onQmlSignalB.connect(cpp_obj.cppSlotB)
    }
 
    //定義的函數(shù)可以作為槽函數(shù)
    function processB(str,value){
        console.log('qml function processB',str,value)
    }
}

注冊(cè)之后就能直接在QML中使用剛才定義的C++類型了,并且可以像QML定義的類型一樣進(jìn)行操作,如信號(hào)槽關(guān)聯(lián)、屬性綁定等。

這個(gè)示例很簡單,點(diǎn)擊鼠標(biāo)左鍵調(diào)用CppObj的sendSignal函數(shù)來發(fā)送信號(hào),QML處理;點(diǎn)擊鼠標(biāo)右鍵QML發(fā)送信號(hào),CppObj處理,下面是操作結(jié)果:

可以看到QML成功的訪問了CppObj的屬性和方法,并能進(jìn)行信號(hào)槽的關(guān)聯(lián)。

第二個(gè)例子:C++中加載QML對(duì)象

文檔如是說,所有QML對(duì)象類型都是源自QObject類型,無論它們是由引擎內(nèi)部實(shí)現(xiàn)還是第三方定義。這意味著QML引擎可以使用Qt元對(duì)象系統(tǒng)動(dòng)態(tài)實(shí)例化任何QML對(duì)象類型并檢查創(chuàng)建的對(duì)象。

這對(duì)于從C ++代碼創(chuàng)建QML對(duì)象非常有用,無論是顯示可以直觀呈現(xiàn)的QML對(duì)象,還是將非可視QML對(duì)象數(shù)據(jù)集成到C ++應(yīng)用程序中。一旦創(chuàng)建了QML對(duì)象,就可以從C ++中檢查它,以便讀取和寫入屬性,調(diào)用方法和接收信號(hào)通知。

可以使用QQmlComponentQQuickView來加載QML文檔。QQmlComponent將QML文檔作為為一個(gè)C++對(duì)象加載,然后可以從C++ 代碼進(jìn)行修改。QQuickView也可以這樣做,但由于QQuickView是一個(gè)基于QWindow的派生類,加載的對(duì)象也將可視化顯示,QQuickView通常用于將一個(gè)可視化的QML對(duì)象集成到應(yīng)用程序的用戶界面中。參見文檔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"
    //自定義信號(hào)  --可以觸發(fā)cpp槽函數(shù)
    signal qmlSendMsg(string arg1,string arg2)
 
    Rectangle {
        anchors.fill: parent
        color: "green"
        objectName: "rect" //用于cpp查找對(duì)象
    }
 
    MouseArea {
        anchors.fill: parent
        onClicked: {
            console.log("qml 點(diǎn)擊鼠標(biāo), 發(fā)送信號(hào) qmlSendMsg")
            root.qmlSendMsg(root.msg,"myarg2")
        }
    }
 
    onHeightChanged: console.log("qml height changed")
    onWidthChanged: console.log("qml width changed")
 
    //QML中的方法可以被cpp調(diào)用,也可以作為槽函數(shù)
    function qml_method(val_arg){
        console.log("qml method runing",val_arg,"return ok")
        return "ok"
    }
    //注意槽函數(shù)參數(shù)為var類型
    function qmlRecvMsg(arg1,arg2){
        console.log("qml slot runing",arg1,arg2)
    }
}

在QML中我定義了一些屬性和方法等,用于測(cè)試。

#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:
    //信號(hào) --用來觸發(fā)qml的函數(shù)
    //注意參數(shù)為var類型,對(duì)應(yīng)qml中js函數(shù)的參數(shù)類型
    void cppSendMsg(const QVariant &arg1,const QVariant &arg2);
 
public slots:
    //槽函數(shù) --用來接收qml的信號(hào)
    void cppRecvMsg(const QString &arg1,const QString &arg2){
        qDebug()<<"CppObject::cppRecvMsg"<<arg1<<arg2;
        qDebug()<<"emit cppSendMsg";
        emit cppSendMsg(arg1,arg2);
    }
};
 
#endif // CPPOBJECT_H

Cpp中定義了一個(gè)槽函數(shù),用來接收QML對(duì)象的信號(hào)。 

#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根對(duì)象的指針
    QObject *qmlObj=view.rootObject();
 
    /*文檔如是說:
    應(yīng)該始終使用QObject::setProperty()、QQmlProperty
    或QMetaProperty::write()來改變QML的屬性值,以確保QML引擎感知屬性的變化。*/
 
    //【1】
    //通過QObject設(shè)置屬性值
    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設(shè)置屬性值
    qDebug()<<"Cpp set qml property width";
    item->setWidth(300);
    //通過QQuickItem獲取屬性值
    qDebug()<<"Cpp get qml property width"<<item->width();
 
    //【3】
    //通過objectName訪問加載的QML對(duì)象
    //QObject::findChildren()可用于查找具有匹配objectName屬性的子項(xiàng)
    QObject *qmlRect=qmlObj->findChild<QObject*>("rect");
    if(qmlRect){
        qDebug()<<"Cpp get rect color"<<qmlRect->property("color");
    }
 
    //【4】
    //調(diào)用QML方法
    QVariant val_return;  //返回值
    QVariant val_arg="GongJianBo";  //參數(shù)值
    //Q_RETURN_ARG()和Q_Arg()參數(shù)必須制定為QVariant類型
    QMetaObject::invokeMethod(qmlObj,
                              "qml_method",
                              Q_RETURN_ARG(QVariant,val_return),
                              Q_ARG(QVariant,val_arg));
    qDebug()<<"QMetaObject::invokeMethod result"<<val_return; //qml函數(shù)中返回“ok”
 
    //【5】
    //關(guān)聯(lián)信號(hào)槽
    CppObject cppObj;
    //關(guān)聯(lián)qml信號(hào)與cpp槽
    //如果信號(hào)參數(shù)為QML對(duì)象類型,信號(hào)用var參數(shù)類型,槽用QVariant類型接收
    QObject::connect(qmlObj,SIGNAL(qmlSendMsg(QString,QString)),
                     &cppObj,SLOT(cppRecvMsg(QString,QString)));
    //關(guān)聯(lián)cpp信號(hào)與qml槽
    //qml中js函數(shù)參數(shù)為var類型,信號(hào)也用QVariant類型
    QObject::connect(&cppObj,SIGNAL(cppSendMsg(QVariant,QVariant)),
                     qmlObj,SLOT(qmlRecvMsg(QVariant,QVariant)));
    //此外,cpp信號(hào)也可以關(guān)聯(lián)qml信號(hào)
 
    return app.exec();
}

然后就把文檔中的東西測(cè)試了下,操作起來很簡單。不過相對(duì)于QML中使用C++對(duì)象來說,感覺作用沒那么大,因?yàn)橐话惆裃ML嵌入到Widgets中才會(huì)做這些操作,但是混合兩個(gè)框架很多坑。下面是我的測(cè)試輸出結(jié)果:

 以上兩種方式應(yīng)該就是最簡單的QML與C++交互應(yīng)用了,對(duì)照文檔或是博客敲一遍代碼可以很容易地理解。

(完結(jié))

代碼完整鏈接(GitHub)如下:

Qml中創(chuàng)建Cpp對(duì)象(Cpp注冊(cè)給Qml):https://github.com/gongjianbo/MyTestCode/tree/master/Qml/QmlCallCpp2020

Cpp中加載Qml對(duì)象(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

(注:文檔中有很多相關(guān)鏈接,此處忽略)

博客: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

到此這篇關(guān)于QML與C++交互的實(shí)現(xiàn)步驟的文章就介紹到這了,更多相關(guān)QML與C++交互內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++中使用function和bind綁定類成員函數(shù)的方法詳解

    C++中使用function和bind綁定類成員函數(shù)的方法詳解

    這篇文章主要介紹了C++中使用function和bind綁定類成員函數(shù)的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • C語言實(shí)現(xiàn)單詞小助手功能完善版

    C語言實(shí)現(xiàn)單詞小助手功能完善版

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)單詞小助手功能的完善版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • C++ new與malloc和delete及free動(dòng)態(tài)內(nèi)存管理及區(qū)別介紹

    C++ new與malloc和delete及free動(dòng)態(tài)內(nèi)存管理及區(qū)別介紹

    這篇文章主要介紹了深入理解C++中的new/delete和malloc/free動(dòng)態(tài)內(nèi)存管理,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • Qt QFile文件操作的具體使用

    Qt QFile文件操作的具體使用

    很多應(yīng)用程序都需要具備操作文件的能力,Qt 框架提供了 QFile 類專門用來操作文件。本文就來詳細(xì)的介紹一下,感興趣的可以了解一下
    2021-11-11
  • Qt?timerEvent實(shí)現(xiàn)簡單秒表功能

    Qt?timerEvent實(shí)現(xiàn)簡單秒表功能

    這篇文章主要為大家詳細(xì)介紹了Qt?timerEvent實(shí)現(xiàn)簡單秒表功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • c語言中unsigned修飾符的使用

    c語言中unsigned修飾符的使用

    在C語言中,unsigned是一種無符號(hào)整數(shù)修飾符,本文主要介紹了c語言中unsigned修飾符的使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-11-11
  • C++11中列表初始化機(jī)制的概念與實(shí)例詳解

    C++11中列表初始化機(jī)制的概念與實(shí)例詳解

    在我們實(shí)際編程中,我們經(jīng)常會(huì)碰到變量初始化的問題,對(duì)于不同的變量初始化的手段多種多樣,下面這篇文章主要給大家介紹了關(guān)于C++11中列表初始化機(jī)制的相關(guān)資料,需要的朋友可以參考下
    2021-11-11
  • C語言異或校驗(yàn)算法的項(xiàng)目實(shí)現(xiàn)

    C語言異或校驗(yàn)算法的項(xiàng)目實(shí)現(xiàn)

    異或校驗(yàn)算法(XOR校驗(yàn))是一種簡單的校驗(yàn)算法,用于檢測(cè)數(shù)據(jù)在傳輸或存儲(chǔ)過程中是否發(fā)生了錯(cuò)誤,本文主要介紹了C語言異或校驗(yàn)算法的項(xiàng)目實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • 關(guān)于C++的重載運(yùn)算符和重載函數(shù)

    關(guān)于C++的重載運(yùn)算符和重載函數(shù)

    一般來說,重載運(yùn)算符在實(shí)際的項(xiàng)目開發(fā)中會(huì)經(jīng)常的用到,但如果某些自定義類型通過簡短幾行代碼重載一些常用的運(yùn)算符(如:+-*/),就能讓編程工作帶來方便,需要的朋友可以參考下本文
    2023-05-05
  • Matlab實(shí)現(xiàn)多子圖同步調(diào)整視角

    Matlab實(shí)現(xiàn)多子圖同步調(diào)整視角

    這篇文章主要為大家介紹了如何利用Matlab實(shí)現(xiàn)多子圖同步調(diào)整視角,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Matlab有一定幫助,需要的可以參考一下
    2022-03-03

最新評(píng)論