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

歡迎訪問 生活随笔!

生活随笔

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

c/c++

QML与Qt C++ 交互机制详解

發(fā)布時間:2023/12/18 c/c++ 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 QML与Qt C++ 交互机制详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

介紹

QML和 C++對象可以通過,signals,slots和 屬性修改進(jìn)行交互。對于一個C++對象,任何數(shù)據(jù)都可以通過Qt的 Meta-Object System暴露給QML(何總方法,后面介紹),同時,任何的QML對象數(shù)據(jù)通過Meta-object system在C++端直接訪問。
在實(shí)際的項目中很多地方會用到QML與Qt C++交互。在這里總結(jié)了若干方法供大家參考,歡迎大家指導(dǎo)和拍磚。

在這里不外乎有三種方法:
1. 把Qt C++中的對象或類型暴露給 QML端,供QML端使用。(官方說法是“嵌入”而非“暴露”,比較文明。- -b)
2. QML中的Signal Handler(相當(dāng)于Qt C++發(fā)送信號給QML端,QML端的Signal Handler進(jìn)行處理)。
3. 在Qt C++端創(chuàng)建QML對象,既然對象都有了。那你想怎么樣它就怎么樣它唄。(沒用過,看起來也不太實(shí)用,不過介紹介紹,有用過的同學(xué)留言哈)。

好,我們開始吧~

知識準(zhǔn)備

別急,讓我們先來看看,一些東西,如果您都知道,可以跳過此節(jié)。
QML API有三個主要成員——QDeclarativeEngine,QDeclarativeComponent和QDeclarativeContext。

QDeclarativeEngine提供了QML的運(yùn)行環(huán)境。
QDeclarativeComponent封裝了QML Documents。
QDeclarativeContext允許程序使用QML組件顯示數(shù)據(jù)。

QML包含一個非常好用的API——QDeclarativeView。通過它,應(yīng)用程序可以很方便的把QML組件嵌入到QGraphicsView中。QDeclarativeView主要用于在應(yīng)用程序開發(fā)過程中進(jìn)行快速原型開發(fā)。

暴露Qt C++的對象或類型給QML

創(chuàng)建需要暴露給QML的數(shù)據(jù)類型

#ifndef MYCLASS_H #define MYCLASS_H #include <QObject> #include <QString> class MyClass : public QObject { Q_OBJECT Q_PROPERTY(QString myString READ myString WRITE setmyString NOTIFY myStringChanged) public: explicit MyClass(QObject *parent = 0); Q_INVOKABLE QString getMyString(); signals: void myStringChanged(); public slots: void setmyString(QString aString); QString myString(); private: QString m_string; }; #endif // MYCLASS_H

若你想數(shù)據(jù)元素中的方法可以被QML直接調(diào)用有2種方法:
1. 在函數(shù)申明前添加 Q_INVOKABLE 宏。
2. 申明成public slots。

QML可以直接訪問改數(shù)據(jù)元素的屬性,該屬性由QPROPERTY所申明。
具體實(shí)現(xiàn)請參考,示例代碼。

暴露已存在的Qt C++對象給QML

//main.cpp MyClass myObj; QDeclarativeEngine *engine=viewer.engine(); QDeclarativeContext *context=engine->rootContext(); context->setContextProperty("myObjectExposeByCXProperty", &myObj);

qml中可以直接使用myObjectExposeByCxProperty對象。

//mainpage.qml ... Button{ ... id:btn1 ... text: qsTr("PROPERTY") //此處調(diào)用myString為MyClass的QPROPERTY的屬性不是方法,所以沒有括號。 onClicked: label.text=myObjectExposeByCXProperty.myString; } ...

注冊Qt C++類類型給QML

另外一種方式是注冊類型 //main.cpp qmlRegisterType<MyClass>("RegisterMyType", 1, 0, "MyClassType"); QML中這樣使用 //mainpage.qml ... import RegisterMyType 1.0 Button{ id:btn2 ... text: qsTr("INOVKABLE") //此處調(diào)用的時INVOKABLE的方法,不是屬性,所以有括號。 onClicked: label.text=myclassExposeByRegType.getMyString(); } //創(chuàng)建對象,由于QML是解釋執(zhí)行的,所以放后面也沒什么關(guān)系。 MyClassType { id:myclassExposeByRegType } 步驟: 1. 導(dǎo)入import。 2. 創(chuàng)建對象。 3. id直接使用。

QML中的Signal Handler

還是使用上面的那例子,在qml中點(diǎn)擊按鈕控件,改變其中對象的字符串,這時候在Qt C++中發(fā)送一個signal信號給qml端,qml端接收到使用signal handler響應(yīng),改變label2的值。具體代碼如下。 qml中修改string的值。 //mainpage.qml Button{ id:btn3 text: qsTr("emit stringchanged signal") onClicked: myObjectExposeByCXProperty.myString="xxxxx"; } Qt C++觸發(fā)信號 //myclass.cpp void MyClass::setmyString(QString aString) { if(aString==m_string) { return; } m_string=aString; emit myStringChanged(); } 連接signal handler響應(yīng) //mainpage.qml Connections { target: myObjectExposeByCXProperty onMyStringChanged:label2.text="Signal handler received" }有參數(shù)形式的:

基本思路與具體步驟

基本思路,把你的Qt C++中的對象暴露給QML端,然后利用signals-slots 進(jìn)行連接,并傳遞消息。具體步驟如下
1 創(chuàng)建自己的對象,如果你的對象是要顯示在QML端,可以繼承QDeclarativeItem,如果只是一個控制類,而不需要顯示在QML端,只需要繼承QObject。這里用到數(shù)據(jù)綁定請參考Using QML Bindings in C++ Applications

#include<QObject> class NetConnectController?: public QObject { Q_OBJECT Q_PROPERTY(int status READ status WRITE setStatus NOTIFY statusChanged)? public: explicit NetConnectController(QObject *parent = 0);void Ready() { emit statusChanged( m_status); } signals: void statusChanged(int aStatus); private: int status() const; void setStatus(int aStatus); private?: //表示網(wǎng)絡(luò)不同的狀態(tài) int m_status; };


2 暴露你的對象給QML

.....? NetConnectController netController QDeclarativeEngine * engine = viewer.engine(); (engine->rootContext())->setContextProperty("NetController",&netController); .....

3在QML中連接Signal-slot

......Connections { target: NetController onStatusChanged:changeStatus(aStatus)//Call JS Function } ......

注意:上面的onStatusChanged?命名格式 “on”+"Qt C++中的signal名字"。在QML端可以直接使用Qt C++端的參數(shù)。例如上面的"aStatus"。

Qt C++中直接調(diào)用QML的函數(shù)

同樣的QML的函數(shù)也可以被Qt C++端調(diào)用。 所有的QML函數(shù)都通過meta-object system暴露Qt C++端,在Qt C++端可以使用QMetaObject::invokeMethod()方法直接調(diào)用。下面就是這樣的一個例子。 // MyItem.qml import QtQuick 1.0 Item { function myQmlFunction(msg) { console.log("Got message:", msg) return "some return value" } } // main.cpp QDeclarativeEngine engine; QDeclarativeComponent component(&engine, "MyItem.qml"); QObject *object = component.create(); QVariant returnedValue; QVariant msg = "Hello from C++"; QMetaObject::invokeMethod(object, "myQmlFunction", Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, msg)); qDebug() << "QML function returned:" << returnedValue.toString(); delete object; 注意:QMetaObject::invokeMethod()方法中的參數(shù)Q_RETURN_ARG()和Q_ARG()都被定義為QVariant類型,此類型是QML函數(shù)的的參數(shù)和返回值的通用數(shù)據(jù)類型。 更多例程可以在SDK的安裝目錄中:\QtSDK\Examples\4.7\declarative\tutorials\extending 看到。

/**********************Q_INVOKABLE與invokeMethod用法*****************/

Qt中經(jīng)常使用的幾個宏: Q_OBJECT, SIGNAL與SLOT, Q_SIGNALS 與 Q_SLOTS, Q_EMIT ,Q_INVOKABLE, Q_PROPERTY。相比其他宏,Q_INVOKABLE 顯得更加神秘,但Q_INVOKABLE的理解與使用變得越來越重要。本文將圍繞Q_INVOKABLE以及相對應(yīng)的invokeMethod展開討論。

Q_INVOKABLE

#define Q_INVOKABLE

重新回顧一下Q_INVOKABLE的定義,它在$QTDIR/src/corelib/kernel/qobjectdefs.h 中,簡單被define,目的在于讓moc識別。

使用Q_INVOKABLE來修飾成員函數(shù),目的在于被修飾的成員函數(shù)能夠被元對象系統(tǒng)所喚起。

QMetaObject::invokeMethod

靜態(tài)方法QMetaObject::invokeMethod() 的定義如下:

  • view plain

  • bool?QMetaObject::invokeMethod?(?QObject?*?obj,?const?char?*?member,Qt::ConnectionType?type,??
  • QGenericReturnArgument?ret,?QGenericArgument?val0?=?QGenericArgument(?0?),?…)??
  • invokeMethod的用法為,嘗試調(diào)用對象obj的方法member(注意member可以為信號或者是槽),如何member可以被調(diào)用,則返回真,否則返回假。QMetaObject::invokeMethod可以是異步調(diào)用,也可以是同步調(diào)用。這取決與它的連接方式Qt::ConnectionType type。如果type為Qt::DirectConnection,則為同步調(diào)用,若為Qt::QueuedConnection,則為異步調(diào)用。例如:

  • view plain

  • QMetaObject::invokeMethod(object,?"methodName",???
  • Qt::QueuedConnection,???
  • Q_ARG(type1,?arg1),???
  • Q_ARG(type2,?arg2));??
  • 上述調(diào)用為異步調(diào)用。請注意,因為上面所示的參數(shù)需要被在構(gòu)建事件時進(jìn)行硬拷貝,參數(shù)的自定義型別所對應(yīng)的類需要提供一個共有的構(gòu)造函數(shù)、析構(gòu)函數(shù)以及拷貝構(gòu)造函數(shù)。而且必須使用注冊Qt型別系統(tǒng)所提供的qRegisterMetaType() 方法來注冊這一自定義型別。

    Q_INVOKABLE與QMetaObject::invokeMethod均由元對象系統(tǒng)喚起。這一機(jī)制在Qt C++/QML混合編程跨線程編程Qt Service Framework 以及?Qt/ HTML5混合編程以及里廣泛使用。

    Qt C++/QML混合編程

    QML中調(diào)用C++方法借助了Qt元對象系統(tǒng)。考慮在QML中使用Qt C++定義的方法,如下代碼所示:

    view plain

  • import?Qt?4.7???
  • import?Shapes?5.0???//自定義模塊??
  • Item?{???
  • ????width:?300;?height:?200??
  • ????Ellipse?{???
  • ?????????x:?50;?y:?35;?width:?200;?height:?100???
  • ????????color:?"blue"???
  • ?????????MouseArea?{???
  • ????????????anchors.fill:?parent??
  • ????????????//?調(diào)用C++中定義的randomColor方法???
  • ????????????onClicked:?parent.color?=?parent.randomColor()????
  • ????????}???
  • ????}??
  • }??
  • 為了讓上述QML代碼成功的調(diào)用下面這段代碼定義的randomColor()函數(shù),最為關(guān)鍵的一點(diǎn)見randomColor方法用Q_INVOKABLE 修飾。

    view plain

  • #include?<QDeclarativeItem?>??
  • class?EllipseItem?:?public?QDeclarativeItem???
  • {???
  • ????Q_OBJECT???
  • public:??
  • ??????Q_INVOKABLE?QColor?randomColor()?const;??
  • ??????…??
  • }??
  • 在跨線程編程中的使用

    我們?nèi)绾握{(diào)用駐足在其他線程里的QObject方法呢?Qt提供了一種非常友好而且干凈的解決方案:向事件隊列post一個事件,事件的處理將以調(diào)用我們所感興趣的方法為主(當(dāng)然這需要線程有一個正在運(yùn)行的事件循環(huán))。而觸發(fā)機(jī)制的實(shí)現(xiàn)是由moc提供的內(nèi)省方法實(shí)現(xiàn)的。因此,只有信號、槽以及被標(biāo)記成Q_INVOKABLE的方法才能夠被其它線程所觸發(fā)調(diào)用。如果你不想通過跨線程的信號、槽這一方法來實(shí)現(xiàn)調(diào)用駐足在其他線程里的QObject方法。另一選擇就是將方法聲明為Q_INVOKABLE,并且在另一線程中用invokeMethod喚起。

    Qt Service Framework

    Qt服務(wù)框架是Qt Mobility 1.0.2版本推出的,一個服務(wù)(service)是一個獨(dú)立的組件提供給客戶端(client)定義好的操作。客戶端可以通過服務(wù)的名稱,版本號和服務(wù)的對象提供的接口來查找服務(wù)。 查找到服務(wù)后,框架啟動服務(wù)并返回一個指針。

    服務(wù)通過插件(plug-ins)來實(shí)現(xiàn)。為了避免客戶端依賴某個具體的庫,服務(wù)必須繼承自QObject。這樣QMetaObject?系統(tǒng)可以用來提供動態(tài)發(fā)現(xiàn)和喚醒服務(wù)的能力。要使QmetaObject機(jī)制充分的工作,服務(wù)必須滿足,其所有的方法都是通過 signal,slot,property 或invokable methodQ_INVOKEBLE來實(shí)現(xiàn)

    其中,最常見的與servicer交互的方法如下:

    view plain

  • QServiceManager?manager;QObject?*storage?;??
  • storage?=?manager.loadInterface("com.nokia.qt.examples.FileStorage");?if?(storage)?????QMetaObject::invokeMethod(storage,?"deleteFile",?Q_ARG(QString,?"/tmp/readme.txt"));??
  • 上面的代碼通過service的元對象提供的invokeMethod方法,調(diào)用文件存儲對象的deleteFile() 方法。客戶端不需要知道對象的類型,因此也沒有鏈接到具體的service庫。? 當(dāng)然在服務(wù)端的deleteFile方法,一定要被標(biāo)記為Q_INVOKEBLE,才能夠被元對象系統(tǒng)識別

    Qt服務(wù)框架的一個亮點(diǎn)是它支持跨進(jìn)程通信,服務(wù)可以接受遠(yuǎn)程進(jìn)程。在服務(wù)管理器上注冊后 進(jìn)程通過signal,slot,invokable method和property來通信,就像本地對象一樣。服務(wù)可以設(shè)定為在客戶端間共享,或針對一個客戶端。??請注意,在Qt服務(wù)框架推出之前,信號、槽以及invokable method僅支持跨線程。 下圖是跨進(jìn)成的服務(wù)/客戶段通信示意圖(圖片來自諾基亞論壇)。這里我們可以清楚的看到,invokable methodQ_INVOKEBLE?是跨進(jìn)城、跨線程對象之間通信的重要利器。

    ?

    總結(jié)

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

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