日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

QML与C++混合编程详解

發(fā)布時間:2025/3/15 c/c++ 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 QML与C++混合编程详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉(zhuǎn)載地址:https://www.cnblogs.com/findumars/p/6090850.html


1、QML與C++為什么要混合編程

QML與C++為什么要混合編程,簡單來說,就是使用QML高效便捷地構(gòu)建UI,而C++則用來實現(xiàn)業(yè)務(wù)邏輯和復(fù)雜算法,下面介紹了兩者間交互的方法與技巧。

2、QML訪問C++概述

Qt集成了QML引擎和Qt元對象系統(tǒng),使得QML很容易從C++中得到擴(kuò)展,在一定的條件下,QML就可以訪問QObject派生類的成員,例如信號、槽函數(shù)、枚舉類型、屬性、成員函數(shù)等。

QML訪問C++有兩個方法:一是在Qt元對象系統(tǒng)中注冊C++類,在QML中實例化、訪問。二是在C++中實例化并設(shè)置為QML上下文屬性,在QML中直接使用。與后者相比,前者可以使C++類在QML中作為一個數(shù)據(jù)類型,例如函數(shù)參數(shù)類型或?qū)傩灶愋?#xff0c;也可以使用其枚舉類型、單例等,功能更強(qiáng)大。

3、如何實現(xiàn)可以被QML訪問的C++

C++類要想被QML訪問,首先必須滿足兩個條件:一是派生自QObject類或QObject類的子類,二是使用Q_OBJECT宏。QObject類是所有Qt對象的基類,作為Qt對象模型的核心,提供了信號與槽機(jī)制等很多重要特性。Q_OBJECT宏必須在private區(qū)(C++默認(rèn)為private)聲明,用來聲明信號與槽,使用Qt元對象系統(tǒng)提供的內(nèi)容,位置一般在語句塊首行。下面例子在QtCreator3.1.2中創(chuàng)建,Projects選擇QtQuickApplication,工程名為Gemini,Component選擇QtQuick2.2,然后在自動生成的文件中添磚加瓦。

信號與槽——

(1)添加頭文件Gemini.h

[cpp]?view plain?copy
  • #ifndef?GEMINI_H??
  • #define?GEMINI_H??
  • //?Gemini.h??
  • #include?<QObject>??
  • #include?<QDebug>??
  • class?Gemini?:?public?QObject??
  • {??
  • ????Q_OBJECT??
  • signals:??
  • ????void?begin();??
  • public?slots:??
  • ????void?doSomething()?{??
  • ????????qDebug()?<<?"Gemini::doSomething()?called";??
  • ????}??
  • };??
  • #endif?//?GEMINI_H??
  • ?

    Gemini類中的信號begin()和槽doSomething()都可以被QML訪問。槽必須聲明為public或protected,信號在C++中使用時要用到emit關(guān)鍵字,但在QML中就是個普通的函數(shù),用法同函數(shù)一樣,信號處理器形式為on<Signal>,Signal首字母大寫。信號不支持重載,多個信號的名字相同而參數(shù)不同時,能夠被識別的只是最后一個信號,與信號的參數(shù)無關(guān)。

    (2)修改main.cpp

    [cpp]?view plain?copy
  • //?main.cpp??
  • #include?<QGuiApplication>??
  • #include?<QQmlApplicationEngine>??
  • #include?<QtQml>??
  • #include?<Gemini.h>??
  • int?main(int?argc,?char?*argv[])??
  • {??
  • ????QGuiApplication?app(argc,?argv);??
  • ????qmlRegisterType<Gemini>("Union.Lotto.Gemini",?1,?0,?"Gemini");??
  • ????QQmlApplicationEngine?engine;??
  • ????engine.load(QUrl(QStringLiteral("qrc:///main.qml")));??
  • ????return?app.exec();??
  • }??
  • 這里把Gemini類注冊(qmlRegisterType)到了Qt元對象系統(tǒng),當(dāng)然也可以先實例化再設(shè)置為QML上下文屬性,相關(guān)內(nèi)容將在后面詳細(xì)介紹。

    (3)修改main.qml

    [sql]?view plain?copy
  • //?main.qml??
  • import?QtQuick?2.2??
  • import?QtQuick.Window?2.1??
  • import?Union.Lotto.Gemini?1.0??
  • Window?{??
  • ????visible:?true??
  • ????width:?360;?height:?360??
  • ????title:?"Union?Lotto?Game"??
  • ????color:?"white"??
  • ????MouseArea?{??
  • ????????anchors.fill:?parent??
  • ????????onClicked:?{??
  • ????????????gemini.begin()??
  • ????????}??
  • ????}??
  • ????Gemini?{??
  • ????????id:?gemini??
  • ????????onBegin:?doSomething()??
  • ????}??
  • }??
  • ?

    Gemini類注冊到Qt元對象系統(tǒng)后,并且在QML文件中導(dǎo)入(import),關(guān)鍵字Gemini就可以在當(dāng)前QML文件中當(dāng)作一種QML類型來用了。例子中有個MouseArea,單擊鼠標(biāo)時會發(fā)送begin()信號,進(jìn)而調(diào)用doSomething()槽函數(shù)。

    枚舉類型——

    (1)修改頭文件Gemini.h

    [cpp]?view plain?copy
  • #ifndef?GEMINI_H??
  • #define?GEMINI_H??
  • //?Gemini.h??
  • #include?<QObject>??
  • #include?<QDebug>??
  • class?Gemini?:?public?QObject??
  • {??
  • ????Q_OBJECT??
  • ????Q_ENUMS(BALL_COLOR)??
  • public:??
  • ????Gemini()?:?m_ballColor(BALL_COLOR_YELLOW)?{??
  • ????????qDebug()?<<?"Gemini::Gemini()?called";??
  • ????}??
  • ????enum?BALL_COLOR?{??
  • ????????BALL_COLOR_YELLOW,??
  • ????????BALL_COLOR_RED,??
  • ????????BALL_COLOR_BLUE,??
  • ????????BALL_COLOR_ALL??
  • ????};??
  • signals:??
  • ????void?begin();??
  • public?slots:??
  • ????void?doSomething(BALL_COLOR?ballColor)?{??
  • ????????qDebug()?<<?"Gemini::doSomething()?called?with"?<<?ballColor;??
  • ????????if(ballColor?!=?m_ballColor)?{??
  • ????????????m_ballColor?=?ballColor;??
  • ????????????qDebug()?<<?"ball?color?changed";??
  • ????????}??
  • ????}??
  • private:??
  • ????BALL_COLOR?m_ballColor;??
  • };??
  • #endif?//?GEMINI_H??
  • Gemini類中添加了public的BALL_COLOR枚舉類型,這個枚舉類型要想在QML中使用,就用到了Q_ENUMS()宏。

    (2)修改main.qml

    [plain]?view plain?copy
  • //?main.qml??
  • import?QtQuick?2.2??
  • import?QtQuick.Window?2.1??
  • import?Union.Lotto.Gemini?1.0??
  • Window?{??
  • ????visible:?true??
  • ????width:?360;?height:?360??
  • ????title:?"Union?Lotto?Game"??
  • ????color:?"white"??
  • ????MouseArea?{??
  • ????????anchors.fill:?parent??
  • ????????onClicked:?{??
  • ????????????gemini.begin()??
  • ????????}??
  • ????}??
  • ????Gemini?{??
  • ????????id:?gemini??
  • ????????onBegin:?doSomething(Gemini.BALL_COLOR_RED)??
  • ????}??
  • }??
  • 在QML中使用枚舉類型的方式是<CLASS_NAME>.<ENUM_VALUE>,例如Gemini.BALL_COLOR_RED

    成員函數(shù)——

    (1)修改頭文件Gemini.h

    [cpp]?view plain?copy
  • #ifndef?GEMINI_H??
  • #define?GEMINI_H??
  • //?Gemini.h??
  • #include?<QObject>??
  • #include?<QDebug>??
  • class?Gemini?:?public?QObject??
  • {??
  • ????Q_OBJECT??
  • ????Q_ENUMS(BALL_COLOR)??
  • public:??
  • ????Gemini()?:?m_ballColor(BALL_COLOR_YELLOW)?{??
  • ????????qDebug()?<<?"Gemini::Gemini()?called";??
  • ????}??
  • ????enum?BALL_COLOR?{??
  • ????????BALL_COLOR_YELLOW,??
  • ????????BALL_COLOR_RED,??
  • ????????BALL_COLOR_BLUE,??
  • ????????BALL_COLOR_ALL??
  • ????};??
  • ????Q_INVOKABLE?void?stop()?{??
  • ????????qDebug()?<<?"Gemini::stop()?called";??
  • ????}??
  • signals:??
  • ????void?begin();??
  • public?slots:??
  • ????void?doSomething(BALL_COLOR?ballColor)?{??
  • ????????qDebug()?<<?"Gemini::doSomething()?called?with"?<<?ballColor;??
  • ????????if(ballColor?!=?m_ballColor)?{??
  • ????????????m_ballColor?=?ballColor;??
  • ????????????qDebug()?<<?"ball?color?changed";??
  • ????????}??
  • ????}??
  • private:??
  • ????BALL_COLOR?m_ballColor;??
  • };??
  • #endif?//?GEMINI_H??
  • Gemini類中添加了成員函數(shù)stop(),在QML中訪問的前提是public或protected成員函數(shù),且使用Q_INVOKABLE宏,位置在函數(shù)返回類型的前面。

    (2)修改main.qml

    [plain]?view plain?copy
  • //?main.qml??
  • import?QtQuick?2.2??
  • import?QtQuick.Window?2.1??
  • import?Union.Lotto.Gemini?1.0??
  • Window?{??
  • ????visible:?true??
  • ????width:?360;?height:?360??
  • ????title:?"Union?Lotto?Game"??
  • ????color:?"white"??
  • ????MouseArea?{??
  • ????????anchors.fill:?parent??
  • ????????onClicked:?{??
  • ????????????gemini.begin()??
  • ????????????gemini.stop()??
  • ????????}??
  • ????}??
  • ????Gemini?{??
  • ????????id:?gemini??
  • ????????onBegin:?doSomething(Gemini.BALL_COLOR_RED)??
  • ????}??
  • }??
  • 在QML中訪問C++的成員函數(shù)的形式是<id>.<method>,例如gemini.stop()。支持函數(shù)重載,這個與信號不同。

    C++類的屬性——

    (1)修改頭文件Gemini.h

    [cpp]?view plain?copy
  • #ifndef?GEMINI_H??
  • #define?GEMINI_H??
  • //?Gemini.h??
  • #include?<QObject>??
  • #include?<QDebug>??
  • class?Gemini?:?public?QObject??
  • {??
  • ????Q_OBJECT??
  • ????Q_ENUMS(BALL_COLOR)??
  • ????Q_PROPERTY(unsigned?int?ballNumber?READ?ballNumber?WRITE?setBallNumber?NOTIFY?ballNumberChanged)??
  • public:??
  • ????Gemini()?:?m_ballColor(BALL_COLOR_YELLOW),?m_ballNumber(0)?{??
  • ????????qDebug()?<<?"Gemini::Gemini()?called";??
  • ????}??
  • ????enum?BALL_COLOR?{??
  • ????????BALL_COLOR_YELLOW,??
  • ????????BALL_COLOR_RED,??
  • ????????BALL_COLOR_BLUE,??
  • ????????BALL_COLOR_ALL??
  • ????};??
  • ????unsigned?int?ballNumber()?const?{??
  • ????????return?m_ballNumber;??
  • ????}??
  • ????void?setBallNumber(const?unsigned?int?&ballNumber)?{??
  • ????????if(ballNumber?!=?m_ballNumber)?{??
  • ????????????m_ballNumber?=?ballNumber;??
  • ????????????emit?ballNumberChanged();??
  • ????????}??
  • ????}??
  • ????Q_INVOKABLE?void?stop()?{??
  • ????????qDebug()?<<?"Gemini::stop()?called";??
  • ????}??
  • signals:??
  • ????void?begin();??
  • ????void?ballNumberChanged();??
  • public?slots:??
  • ????void?doSomething(BALL_COLOR?ballColor)?{??
  • ????????qDebug()?<<?"Gemini::doSomething()?called?with"?<<?ballColor;??
  • ????????if(ballColor?!=?m_ballColor)?{??
  • ????????????m_ballColor?=?ballColor;??
  • ????????????qDebug()?<<?"ball?color?changed";??
  • ????????}??
  • ????}??
  • private:??
  • ????BALL_COLOR?m_ballColor;??
  • ????unsigned?int?m_ballNumber;??
  • };??
  • #endif?//?GEMINI_H??
  • Gemini類中添加了Q_PROPERTY()宏,用來在QObject派生類中聲明屬性,這個屬性如同類的數(shù)據(jù)成員一樣,但它又有一些額外的特性可通過Qt元對象系統(tǒng)來訪問。

    下面是Q_PROPERTY()宏的原型:

    [cpp]?view plain?copy
  • Q_PROPERTY()(type?name??
  • ??(READ?getFunction?[WRITE?setFunction]?|??
  • ?????????????MEMBER?memberName?[(READ?getFunction?|?WRITE?setFunction)])??
  • ????????????[RESET?resetFunction]??
  • ????????????[NOTIFY?notifySignal]??
  • ????????????[REVISION?int]??
  • ????????????[DESIGNABLE?bool]??
  • ????????????[SCRIPTABLE?bool]??
  • ????????????[STORED?bool]??
  • ????????????[USER?bool]??
  • ????????????[CONSTANT]??
  • ????????????[FINAL])??
  • 屬性的type、name是必需的,其它是可選項,常用的有READ、WRITE、NOTIFY。屬性的type可以是QVariant支持的任何類型,也可以是自定義類型,包括自定義類、列表類型、組屬性等。另外,屬性的READ、WRITE、RESET是可以被繼承的,也可以是虛函數(shù),這些特性并不常用。

    READ:讀取屬性值,如果沒有設(shè)置MEMBER的話,它是必需的。一般情況下,函數(shù)是個const函數(shù),返回值類型必須是屬性本身的類型或這個類型的const引用,沒有參數(shù)。

    WRITE:設(shè)置屬性值,可選項。函數(shù)必須返回void,有且僅有一個參數(shù),參數(shù)類型必須是屬性本身的類型或這個類型的指針或引用。

    NOTIFY:與屬性關(guān)聯(lián)的可選信號。這個信號必須在類中聲明過,當(dāng)屬性值改變時,就可觸發(fā)這個信號,可以沒有參數(shù),有參數(shù)的話只能是一個類型同屬性本身類型的參數(shù),用來記錄屬性改變后的值。

    Q_PROPERTY()的詳細(xì)用法可參考如下網(wǎng)址:

    http://doc.qt.io/qt-5/properties.html#qt-s-property-system

    (2)修改main.qml

    [sql]?view plain?copy
  • //?main.qml??
  • import?QtQuick?2.2??
  • import?QtQuick.Window?2.1??
  • import?Union.Lotto.Gemini?1.0??
  • Window?{??
  • ????visible:?true??
  • ????width:?360;?height:?360??
  • ????title:?"Union?Lotto?Game"??
  • ????color:?"white"??
  • ????MouseArea?{??
  • ????????anchors.fill:?parent??
  • ????????onClicked:?{??
  • ????????????gemini.begin()??
  • ????????????gemini.stop()??
  • ????????????gemini.ballNumber?=?10??
  • ????????}??
  • ????}??
  • ????Gemini?{??
  • ????????id:?gemini??
  • ????????onBegin:?doSomething(Gemini.BALL_COLOR_RED)??
  • ????????onBallNumberChanged:?console.log("new?ball?number?is",?ballNumber)?//?10??
  • ????????Component.onCompleted:?console.log("default?ball?number?is",?ballNumber)?//?0??
  • ????}??
  • }??
  • Gemini類中的ballNumber屬性可以在QML中訪問、修改,訪問時調(diào)用了ballNumber()函數(shù),修改時調(diào)用了setBallNumber()函數(shù),同時還發(fā)送了一個信號來自動更新這個屬性值。

    4、注冊C++類為QML類型

    QObject派生類可以注冊到Qt元對象系統(tǒng),使得該類在QML中同其它內(nèi)建類型一樣,可以作為一個數(shù)據(jù)類型來使用。QML引擎允許注冊可實例化的類型,也可以是不可實例化的類型,常見的注冊函數(shù)有:

    [cpp]?view plain?copy
  • qmlRegisterInterface()??
  • qmlRegisterRevision()??
  • qmlRegisterSingletonType()??
  • qmlRegisterType()??
  • qmlRegisterTypeNotAvailable()??
  • qmlRegisterUncreatableType()??
  • 這些注冊函數(shù)各有其用,可根據(jù)實際需要選擇,使用時需要包含<QtQml>。常用的為qmlRegisterType(),它有三個重載函數(shù),這里只介紹其一:

    [cpp]?view plain?copy
  • ??template<typename?T>??
  • ??int?qmlRegisterType(const?char?*uri,??
  • int?versionMajor,??
  • int?versionMinor,???
  • ???????const?char?*qmlName);??
  • 這個模板函數(shù)注冊C++類到Qt元對象系統(tǒng)中,uri是需要導(dǎo)入到QML中的庫名,versionMajor和versionMinor是其版本數(shù)字,qmlName是在QML中可以使用的類型名。例如上面例子main.cpp中的代碼:

    [cpp]?view plain?copy
  • qmlRegisterType<Gemini>("Union.Lotto.Gemini",?1,?0,?"Gemini");??
  • main.cpp中將Gemini類注冊為在QML中可以使用的Gemini類型,主版本為1,次版本為0,庫的名字是Union.Lotto.Gemini。main.qml中導(dǎo)入了這個庫,使用Gemini構(gòu)造了一個對象,id為gemini,這樣就可以借助id來訪問C++了。

    注冊動作必須在QML上下文創(chuàng)建之前,否則無效。

    另外:QQuickView為QtQuickUI提供了一個窗口,可以方便地加載QML文件并顯示其界面。QApplication派生自QGuiApplication,而QGuiApplication又派生自QCoreApplication,這三個類是常見的管理Qt應(yīng)用程序的類。QQmlApplicationEngine可以方便地從一個單一的QML文件中加載應(yīng)用程序,它派生自QQmlEngine,QQmlEngine則提供了加載QML組件的環(huán)境,可以與QQmlComponent、QQmlContext等一起使用。

    5、QML上下文屬性設(shè)置

    在C++應(yīng)用程序加載QML對象時,我們可以直接嵌入一些C++數(shù)據(jù)來給QML使用,這里需要用到QQmlContext::setContextProperty(),即設(shè)置QML上下問屬性,它可以是一個簡單的類型,也可以是任何我們自定義的類對象。

    (1)修改main.cpp

    [cpp]?view plain?copy
  • //?main.cpp??
  • #include?<QGuiApplication>??
  • #include?<QQuickView>??
  • #include?<QQmlContext>??
  • #include?<Gemini.h>??
  • int?main(int?argc,?char?*argv[])??
  • {??
  • ????QGuiApplication?app(argc,?argv);??
  • ????QQuickView?view;??
  • ????Gemini?gemini;??
  • ????view.rootContext()->setContextProperty("gemini",?&gemini);??
  • ????view.setSource(QUrl(QStringLiteral("qrc:///main.qml")));??
  • ????view.show();??
  • ????return?app.exec();??
  • }??
  • 徹底修改一下main.cpp吧,這里使用了QQuickView,注意頭文件的變化,Gemini類先實例化為gemini對象,然后注冊為QML上下文屬性。

    (2)修改main.qml

    [plain]?view plain?copy
  • //?main.qml??
  • import?QtQuick?2.2??
  • Item?{??
  • ????width:?360;?height:?360??
  • ????MouseArea?{??
  • ????????anchors.fill:?parent??
  • ????????onClicked:?{??
  • ????????????gemini.begin()??
  • ????????????gemini.stop()??
  • ????????}??
  • ????}??
  • ????Connections?{??
  • ????????target:?gemini??
  • ????????onBegin:console.log("aaaa")??
  • ????}??
  • }??
  • 既然main.cpp修改了那么多東西,main.qml也要做相應(yīng)的修改,在main.qml中不能使用Gemini類型來實例化了,也不能調(diào)用doSomething()槽函數(shù)了,因為doSomething()函數(shù)中的枚舉類型在QML中是訪問不到的,正確的用法是通過QML上下文屬性“gemini”來訪問C++,可以訪問信號begin()和成員函數(shù)stop(),此時的信號處理器就需要用Connections來處理了,如上面例子中所示。

    6、C++訪問QML

    同樣,在C++中也可以訪問QML中的屬性、函數(shù)和信號。

    在C++中加載QML文件可以用QQmlComponent或QQuickView,然后就可以在C++中訪問QML對象了。QQuickView提供了一個顯示用戶界面的窗口,而QQmlComponent沒有。

    QQuickView::rootObject()返回了組件實例,是一個有用的函數(shù)。前面的例子中已經(jīng)使用過QQuickView了,下面的例子介紹QQmlComponent的用法。

    使用QQmlComponent——

    修改main.cpp

    [cpp]?view plain?copy
  • //?main.cpp??
  • #include?<QGuiApplication>??
  • #include?<QtQml>??
  • #include?<Gemini.h>??
  • int?main(int?argc,?char?*argv[])??
  • {??
  • ????QGuiApplication?app(argc,?argv);??
  • ????qmlRegisterType<Gemini>("Union.Lotto.Gemini",?1,?0,?"Gemini");??
  • ????QQmlEngine?engine;??
  • ????//?set?qml?context?property??
  • ????//?Gemini?aGemini;??
  • ????//?engine.rootContext()->setContextProperty("aGemini",?&aGemini);??
  • ????QQmlComponent?component(&engine,?QUrl(QStringLiteral("qrc:///main.qml")));??
  • ????component.create();??
  • ????return?app.exec();??
  • }??
  • 例子中注釋的部分是設(shè)置QML上下文屬性的方法。

    在C++中訪問QML中的屬性——

    在C++中加載了QML文件并進(jìn)行組件實例化后,就可以在C++中訪問、修改這個實例的屬性值了,可以是QML內(nèi)建屬性,也可以是自定義屬性。

    (1)修改main.qml

    [plain]?view plain?copy
  • //?main.qml??
  • import?QtQuick?2.2??
  • import?QtQuick.Window?2.1??
  • import?Union.Lotto.Gemini?1.0??
  • Window?{??
  • ????visible:?true??
  • ????width:?360;?height:?360??
  • ????title:?"Union?Lotto?Game"??
  • ????color:?"white"??
  • ????Rectangle?{??
  • ????????objectName:?"rect"??
  • ????????anchors.fill:?parent??
  • ????????color:?"yellow"??
  • ????}??
  • ????MouseArea?{??
  • ????????anchors.fill:?parent??
  • ????????onClicked:?{??
  • ????????????gemini.begin()??
  • ????????????gemini.stop()??
  • ????????????gemini.ballNumber?=?10??
  • ????????}??
  • ????}??
  • ????Gemini?{??
  • ????????id:?gemini??
  • ????????onBegin:?doSomething(Gemini.BALL_COLOR_RED)??
  • ????????onBallNumberChanged:?console.log("new?ball?number?is",?ballNumber)?//?10??
  • ????????Component.onCompleted:?console.log("default?ball?number?is",?ballNumber)?//?0??
  • ????}??
  • }??
  • 在main.qml中添加了一個Rectangle,設(shè)置objectName屬性值為“rect”,這個值是為了在C++中能夠找到這個Rectangle

    (2)修改main.cpp

    [cpp]?view plain?copy
  • //?main.cpp??
  • #include?<QGuiApplication>??
  • #include?<QtQml>??
  • #include?<Gemini.h>??
  • int?main(int?argc,?char?*argv[])??
  • {??
  • ????QGuiApplication?app(argc,?argv);??
  • ????qmlRegisterType<Gemini>("Union.Lotto.Gemini",?1,?0,?"Gemini");??
  • ????QQmlEngine?engine;??
  • ????//?set?qml?context?property??
  • ????//?Gemini?aGemini;??
  • ????//?engine.rootContext()->setContextProperty("aGemini",?&aGemini);??
  • ????QQmlComponent?component(&engine,?QUrl(QStringLiteral("qrc:///main.qml")));??
  • ????QObject?*object?=?component.create();??
  • ????qDebug()?<<?"width?value?is"?<<?object->property("width").toInt();??
  • ????object->setProperty("width",?500);??
  • ????qDebug()?<<?"height?value?is"?<<?QQmlProperty::read(object,?"height").toInt();??
  • ????QQmlProperty::write(object,?"height",?500);??
  • ????QObject?*rect?=?object->findChild<QObject*>("rect");??
  • ????if(rect)?{??
  • ????????rect->setProperty("color",?"black");??
  • ????}??
  • ????return?app.exec();??
  • }??
  • 首先,使用了QObject::property()/setProperty()來讀取、修改width屬性值。

    接著,使用了QQmlProperty::read()/write()來讀取、修改height屬性值。

    另外,如果某個對象的類型是QQuickItem,例如QQuickView::rootObject()的返回值,這時就可以使用QQuickItem::width/setWidth()來訪問、修改width屬性值了。

    有時候,QML組件是一個復(fù)雜的樹型結(jié)構(gòu),包含兄弟組件和孩子組件,我們可以使用QObject::findchild()/findchildren()來查找,如上面例子所示。

    在C++中訪問QML中的函數(shù)與信號——

    在C++中,使用QMetaObject::invokeMethod()可以調(diào)用QML中的函數(shù),從QML傳遞過來的函數(shù)參數(shù)和返回值會被轉(zhuǎn)換為C++中的QVariant類型,成功返回true,參數(shù)不正確或被調(diào)用函數(shù)名錯誤返回false,invokeMethod()共有四個重載函數(shù),用法相似。必須使用Q_ARG()宏來聲明函數(shù)參數(shù),用Q_RETURN_ARG()宏來聲明函數(shù)返回值,其原型如下:

    [cpp]?view plain?copy
  • QGenericArgument???????????Q_ARG(Type,?const?Type?&?value)??
  • QGenericReturnArgument?????Q_RETURN_ARG(Type,?Type?&?value)??
  • 使用QObject::connect()可以連接QML中的信號,connect()共有四個重載函數(shù),它們都是靜態(tài)函數(shù)。必須使用SIGNAL()宏來聲明信號,SLOT()宏聲明槽函數(shù)。

    使用QObject::disconnect()可以解除信號與槽函數(shù)的連接。

    (1)修改main.qml

    [plain]?view plain?copy
  • import?QtQuick?2.2??
  • import?QtQuick.Window?2.1??
  • import?Union.Lotto.Gemini?1.0??
  • Window?{??
  • ????visible:?true??
  • ????width:?360;?height:?360??
  • ????title:?"Union?Lotto?Game"??
  • ????color:?"white"??
  • ????signal?qmlSignal(string?message)??
  • ????onQmlSignal:?console.log("qml?signal?message?is",?message)?//?this?is?a?qml?signal??
  • ????function?qmlFunction(parameter)?{??
  • ????????console.log("qml?function?parameter?is",?parameter)?//?Hello?from?C++??
  • ????????return?"function?from?qml"??
  • ????}??
  • ????Rectangle?{??
  • ????????objectName:?"rect"??
  • ????????anchors.fill:?parent??
  • ????????color:?"yellow"??
  • ????}??
  • ????MouseArea?{??
  • ????????anchors.fill:?parent??
  • ????????onClicked:?{??
  • ????????????gemini.begin()??
  • ????????????gemini.stop()??
  • ????????????gemini.ballNumber?=?10??
  • ????????????qmlSignal("this?is?a?qml?signal")??
  • ????????}??
  • ????}??
  • ????Gemini?{??
  • ????????id:?gemini??
  • ????????onBegin:?doSomething(Gemini.BALL_COLOR_RED)??
  • ????????onBallNumberChanged:?console.log("new?ball?number?is",?ballNumber)?//?10??
  • ????????Component.onCompleted:?console.log("default?ball?number?is",?ballNumber)?//?0??
  • ????}??
  • }??
  • main.qml中添加了qmlSignal()信號和qmlFunction()函數(shù),信號在QML中發(fā)送,函數(shù)在C++中調(diào)用。

    (2)修改Gemini.h

    [cpp]?view plain?copy
  • #ifndef?GEMINI_H??
  • #define?GEMINI_H??
  • //?Gemini.h??
  • #include?<QObject>??
  • #include?<QDebug>??
  • class?Gemini?:?public?QObject??
  • {??
  • ????Q_OBJECT??
  • ????Q_ENUMS(BALL_COLOR)??
  • ????Q_PROPERTY(unsigned?int?ballNumber?READ?ballNumber?WRITE?setBallNumber?NOTIFY?ballNumberChanged)??
  • public:??
  • ????Gemini()?:?m_ballColor(BALL_COLOR_YELLOW),?m_ballNumber(0)?{??
  • ????????qDebug()?<<?"Gemini::Gemini()?called";??
  • ????}??
  • ????enum?BALL_COLOR?{??
  • ????????BALL_COLOR_YELLOW,??
  • ????????BALL_COLOR_RED,??
  • ????????BALL_COLOR_BLUE,??
  • ????????BALL_COLOR_ALL??
  • ????};??
  • ????unsigned?int?ballNumber()?const?{??
  • ????????return?m_ballNumber;??
  • ????}??
  • ????void?setBallNumber(const?unsigned?int?&ballNumber)?{??
  • ????????if(ballNumber?!=?m_ballNumber)?{??
  • ????????????m_ballNumber?=?ballNumber;??
  • ????????????emit?ballNumberChanged();??
  • ????????}??
  • ????}??
  • ????Q_INVOKABLE?void?stop()?{??
  • ????????qDebug()?<<?"Gemini::stop()?called";??
  • ????}??
  • signals:??
  • ????void?begin();??
  • ????void?ballNumberChanged();??
  • public?slots:??
  • ????void?doSomething(BALL_COLOR?ballColor)?{??
  • ????????qDebug()?<<?"Gemini::doSomething()?called?with"?<<?ballColor;??
  • ????????if(ballColor?!=?m_ballColor)?{??
  • ????????????m_ballColor?=?ballColor;??
  • ????????????qDebug()?<<?"ball?color?changed";??
  • ????????}??
  • ????}??
  • ????void?cppSlot(const?QString?&message)?{??
  • ????????qDebug()?<<?"Called?the?C++?slot?with?message:"?<<?message;?//?this?is?a?qml?signal??
  • ????}??
  • private:??
  • ????BALL_COLOR?m_ballColor;??
  • ????unsigned?int?m_ballNumber;??
  • };??
  • #endif?//?GEMINI_H??
  • Gemini類中添加了cppSlot()槽函數(shù),將要在main.cpp中與QML的信號connect

    (3)修改main.cpp

    [cpp]?view plain?copy
  • #include?<QGuiApplication>??
  • #include?<QtQml>??
  • #include?<Gemini.h>??
  • int?main(int?argc,?char?*argv[])??
  • {??
  • ????QGuiApplication?app(argc,?argv);??
  • ????qmlRegisterType<Gemini>("Union.Lotto.Gemini",?1,?0,?"Gemini");??
  • ????QQmlEngine?engine;??
  • ????//?set?qml?context?property??
  • ????//?Gemini?aGemini;??
  • ????//?engine.rootContext()->setContextProperty("aGemini",?&aGemini);??
  • ????QQmlComponent?component(&engine,?QUrl(QStringLiteral("qrc:///main.qml")));??
  • ????QObject?*object?=?component.create();??
  • ????qDebug()?<<?"width?value?is"?<<?object->property("width").toInt();??
  • ????object->setProperty("width",?500);??
  • ????qDebug()?<<?"height?value?is"?<<?QQmlProperty::read(object,?"height").toInt();??
  • ????QQmlProperty::write(object,?"height",?500);??
  • ????QObject?*rect?=?object->findChild<QObject*>("rect");??
  • ????if(rect)?{??
  • ????????rect->setProperty("color",?"black");??
  • ????}??
  • ????QVariant?returnedValue;??
  • ????QVariant?message?=?"Hello?from?C++";??
  • ????QMetaObject::invokeMethod(object,?"qmlFunction",??
  • ??????????????????????????????Q_RETURN_ARG(QVariant,?returnedValue),??
  • ??????????????????????????????Q_ARG(QVariant,?message));??
  • ????qDebug()?<<?"returnedValue?is"?<<?returnedValue.toString();?//?function?from?qml??
  • ????Gemini?test;??
  • ????QObject::connect(object,?SIGNAL(qmlSignal(QString)),??
  • ?????????????????????&test,?SLOT(cppSlot(QString)));??
  • ????return?app.exec();??
  • }??
  • 在main.cpp中添加了QMeta::invokeMethod()和QObject::connect()來分別訪問QML中函數(shù)和信號。

    7、總結(jié)

    本文主要介紹了QML與C++混合編程常用的方法與技巧,在使用過程中有幾點值得注意:

    ?????????自定義類一定要派生自QObject類或其子類。

    ?????????必須使用Q_OBJECT宏。

    ?????????注冊自定義類到Qt元對象系統(tǒng)或設(shè)置自定義類對象實例為QML上下文屬性是必須的。

    ?????????兩者交互進(jìn)行數(shù)據(jù)傳遞時,要符合QML與C++間數(shù)據(jù)類型的轉(zhuǎn)換規(guī)則。

    ?

    http://blog.csdn.net/ieearth/article/details/42243553

    總結(jié)

    以上是生活随笔為你收集整理的QML与C++混合编程详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。