在 Qt/Qt Quick宏淺議 一文中,我們將介紹Qt中經(jīng)常使用的幾個(gè)宏: Q_OBJECT, SIGNAL與SLOT, Q_SIGNALS 與 Q_SLOTS, Q_EMIT ,Q_INVOKABLE, Q_PROPERTY。相比其他宏,Q_INVOKABLE 顯得更加神秘,但Q_INVOKABLE的理解與使用變得越來(lái)越重要。本文將圍繞Q_INVOKABLE以及相對(duì)應(yīng)的invokeMethod展開(kāi)討論。
Q_INVOKABLE
#define Q_INVOKABLE
重新回顧一下Q_INVOKABLE的定義,它在$QTDIR/src/corelib/kernel/qobjectdefs.h 中,簡(jiǎn)單被define,目的在于讓moc識(shí)別。
使用Q_INVOKABLE來(lái)修飾成員函數(shù),目的在于被修飾的成員函數(shù)能夠被元對(duì)象系統(tǒng)所喚起。
QMetaObject::invokeMethod
靜態(tài)方法QMetaObject::invokeMethod() 的定義如下:
- bool QMetaObject::invokeMethod(QObject*obj, const char *member,Qt::ConnectionTypetype,
- QGenericReturnArgumentret,QGenericArgumentval0=QGenericArgument(0),…)
invokeMethod的用法為,嘗試調(diào)用對(duì)象obj的方法member(注意member可以為信號(hào)或者是槽),如何member可以被調(diào)用,則返回真,否則返回假。QMetaObject::invokeMethod可以是異步調(diào)用,也可以是同步調(diào)用。這取決與它的連接方式Qt::ConnectionType type。如果type為Qt::DirectConnection,則為同步調(diào)用,若為Qt::QueuedConnection,則為異步調(diào)用。例如:
- QMetaObject::invokeMethod(object, "methodName" ,
- Qt::QueuedConnection,
- Q_ARG(type1,arg1),
- Q_ARG(type2,arg2));
上述調(diào)用為異步調(diào)用。請(qǐng)注意,因?yàn)樯厦嫠镜膮?shù)需要被在構(gòu)建事件時(shí)進(jìn)行硬拷貝,參數(shù)的自定義型別所對(duì)應(yīng)的類(lèi)需要提供一個(gè)共有的構(gòu)造函數(shù)、析構(gòu)函數(shù)以及拷貝構(gòu)造函數(shù)。而且必須使用注冊(cè)Qt型別系統(tǒng)所提供的qRegisterMetaType() 方法來(lái)注冊(cè)這一自定義型別。
Q_INVOKABLE與QMetaObject::invokeMethod均由元對(duì)象系統(tǒng)喚起。這一機(jī)制在 Qt C++/QML混合編程 , 跨線程編程 , Qt Service Framework 以及Qt/ HTML5混合編程 以及里廣泛使用。
Qt C++/QML混合編程
QML中調(diào)用C++方法借助了Qt元對(duì)象系統(tǒng)。考慮在QML中使用Qt C++定義的方法,如下代碼所示:
- importQt4.7
- importShapes5.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)見(jiàn)randomColor方法用Q_INVOKABLE 修飾。
- #include<QDeclarativeItem>
- class EllipseItem: public QDeclarativeItem
- {
- Q_OBJECT
- public :
- Q_INVOKABLEQColorrandomColor() const ;
- …
- }
更多細(xì)節(jié),請(qǐng)參看我的另一篇博文: QML與C++混合編程使用
在跨線程編程中的使用
我們?nèi)绾握{(diào)用駐足在其他線程里的QObject方法呢?Qt提供了一種非常友好而且干凈的解決方案:向事件隊(duì)列post一個(gè)事件,事件的處理將以調(diào)用我們所感興趣的方法為主(當(dāng)然這需要線程有一個(gè)正在運(yùn)行的事件循環(huán))。而觸發(fā)機(jī)制的實(shí)現(xiàn)是由moc提供的內(nèi)省方法實(shí)現(xiàn)的。因此,只有信號(hào)、槽以及 被標(biāo)記成Q_INVOKABLE的方法才能夠被其它線程所觸發(fā)調(diào)用 。如果你不想通過(guò)跨線程的信號(hào)、槽這一方法來(lái)實(shí)現(xiàn)調(diào)用駐足在其他線程里的QObject方法。另一選擇就是將方法聲明為Q_INVOKABLE,并且在另一線程中用 invokeMethod 喚起。
更多細(xì)節(jié),譯文 事件循環(huán)與線程
Qt Service Framework
Qt服務(wù)框架是Qt Mobility 1.0.2版本推出的,一個(gè)服務(wù)(service)是一個(gè)獨(dú)立的組件提供給客戶(hù)端(client)定義好的操作。客戶(hù)端可以通過(guò)服務(wù)的名稱(chēng),版本號(hào)和服務(wù)的對(duì)象提供的接口來(lái)查找服務(wù)。 查找到服務(wù)后,框架啟動(dòng)服務(wù)并返回一個(gè)指針。
服務(wù)通過(guò)插件(plug-ins)來(lái)實(shí)現(xiàn)。為了避免客戶(hù)端依賴(lài)某個(gè)具體的庫(kù),服務(wù)必須繼承自QObject。這樣 QMetaObject 系統(tǒng)可以用來(lái)提供動(dòng)態(tài)發(fā)現(xiàn)和喚醒服務(wù)的能力。要使QmetaObject機(jī)制充分的工作,服務(wù)必須滿(mǎn)足,其所有的方法都是通過(guò) signal,slot,property 或 invokable method 和 Q_INVOKEBLE 來(lái)實(shí)現(xiàn)
其中,最常見(jiàn)的與servicer交互的方法如下:
- QServiceManagermanager;QObject*storage;
- storage=manager.loadInterface( "com.nokia.qt.examples.FileStorage" ); if (storage)QMetaObject::invokeMethod(storage, "deleteFile" ,Q_ARG(QString, "/tmp/readme.txt" ));
上面的代碼通過(guò)service的元對(duì)象提供的invokeMethod方法,調(diào)用文件存儲(chǔ)對(duì)象的deleteFile() 方法。客戶(hù)端不需要知道對(duì)象的類(lèi)型,因此也沒(méi)有鏈接到具體的service庫(kù)。 當(dāng)然在服務(wù)端的deleteFile方法,一定要被標(biāo)記為 Q_INVOKEBLE, 才能夠被元對(duì)象系統(tǒng)識(shí)別
Qt服務(wù)框架的一個(gè)亮點(diǎn)是它支持 跨進(jìn)程通信 ,服務(wù)可以接受遠(yuǎn)程進(jìn)程。在服務(wù)管理器上注冊(cè)后 進(jìn)程通過(guò)signal,slot, invokable method 和property來(lái)通信,就像本地對(duì)象一樣。服務(wù)可以設(shè)定為在客戶(hù)端間共享,或針對(duì)一個(gè)客戶(hù)端。 請(qǐng)注意 ,在Qt服務(wù)框架推出之前,信號(hào)、槽以及invokable method僅支持跨線程。 下圖是跨進(jìn)成的服務(wù)/客戶(hù)段通信示意圖(圖片來(lái)自諾基亞論壇)。這里我們可以清楚的看到, invokable method 和 Q_INVOKEBLE 是跨進(jìn)城、跨線程對(duì)象之間通信的重要利器。
有關(guān)Qt Service Framework的更多討論和用例,請(qǐng)參見(jiàn) Qt Service Framework文檔
請(qǐng)尊重原創(chuàng)作品和譯文。轉(zhuǎn)載請(qǐng)保持文章完整性,并以超鏈接形式注明原始作者
地址
http://blog.csdn.net/changsheng230
,方便其他朋友提問(wèn)和指正。
在 Qt/Qt Quick宏淺議 一文中,我們將介紹Qt中經(jīng)常使用的幾個(gè)宏: Q_OBJECT, SIGNAL與SLOT, Q_SIGNALS 與 Q_SLOTS, Q_EMIT ,Q_INVOKABLE, Q_PROPERTY。相比其他宏,Q_INVOKABLE 顯得更加神秘,但Q_INVOKABLE的理解與使用變得越來(lái)越重要。本文將圍繞Q_INVOKABLE以及相對(duì)應(yīng)的invokeMethod展開(kāi)討論。
Q_INVOKABLE
#define Q_INVOKABLE
重新回顧一下Q_INVOKABLE的定義,它在$QTDIR/src/corelib/kernel/qobjectdefs.h 中,簡(jiǎn)單被define,目的在于讓moc識(shí)別。
使用Q_INVOKABLE來(lái)修飾成員函數(shù),目的在于被修飾的成員函數(shù)能夠被元對(duì)象系統(tǒng)所喚起。
QMetaObject::invokeMethod
靜態(tài)方法QMetaObject::invokeMethod() 的定義如下:
- bool QMetaObject::invokeMethod(QObject*obj, const char *member,Qt::ConnectionTypetype,
- QGenericReturnArgumentret,QGenericArgumentval0=QGenericArgument(0),…)
invokeMethod的用法為,嘗試調(diào)用對(duì)象obj的方法member(注意member可以為信號(hào)或者是槽),如何member可以被調(diào)用,則返回真,否則返回假。QMetaObject::invokeMethod可以是異步調(diào)用,也可以是同步調(diào)用。這取決與它的連接方式Qt::ConnectionType type。如果type為Qt::DirectConnection,則為同步調(diào)用,若為Qt::QueuedConnection,則為異步調(diào)用。例如:
- QMetaObject::invokeMethod(object, "methodName" ,
- Qt::QueuedConnection,
- Q_ARG(type1,arg1),
- Q_ARG(type2,arg2));
上述調(diào)用為異步調(diào)用。請(qǐng)注意,因?yàn)樯厦嫠镜膮?shù)需要被在構(gòu)建事件時(shí)進(jìn)行硬拷貝,參數(shù)的自定義型別所對(duì)應(yīng)的類(lèi)需要提供一個(gè)共有的構(gòu)造函數(shù)、析構(gòu)函數(shù)以及拷貝構(gòu)造函數(shù)。而且必須使用注冊(cè)Qt型別系統(tǒng)所提供的qRegisterMetaType() 方法來(lái)注冊(cè)這一自定義型別。
Q_INVOKABLE與QMetaObject::invokeMethod均由元對(duì)象系統(tǒng)喚起。這一機(jī)制在 Qt C++/QML混合編程 , 跨線程編程 , Qt Service Framework 以及Qt/ HTML5混合編程 以及里廣泛使用。
Qt C++/QML混合編程
QML中調(diào)用C++方法借助了Qt元對(duì)象系統(tǒng)。考慮在QML中使用Qt C++定義的方法,如下代碼所示:
- importQt4.7
- importShapes5.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)見(jiàn)randomColor方法用Q_INVOKABLE 修飾。
- #include<QDeclarativeItem>
- class EllipseItem: public QDeclarativeItem
- {
- Q_OBJECT
- public :
- Q_INVOKABLEQColorrandomColor() const ;
- …
- }
更多細(xì)節(jié),請(qǐng)參看我的另一篇博文: QML與C++混合編程使用
在跨線程編程中的使用
我們?nèi)绾握{(diào)用駐足在其他線程里的QObject方法呢?Qt提供了一種非常友好而且干凈的解決方案:向事件隊(duì)列post一個(gè)事件,事件的處理將以調(diào)用我們所感興趣的方法為主(當(dāng)然這需要線程有一個(gè)正在運(yùn)行的事件循環(huán))。而觸發(fā)機(jī)制的實(shí)現(xiàn)是由moc提供的內(nèi)省方法實(shí)現(xiàn)的。因此,只有信號(hào)、槽以及 被標(biāo)記成Q_INVOKABLE的方法才能夠被其它線程所觸發(fā)調(diào)用 。如果你不想通過(guò)跨線程的信號(hào)、槽這一方法來(lái)實(shí)現(xiàn)調(diào)用駐足在其他線程里的QObject方法。另一選擇就是將方法聲明為Q_INVOKABLE,并且在另一線程中用 invokeMethod 喚起。
更多細(xì)節(jié),譯文 事件循環(huán)與線程
Qt Service Framework
Qt服務(wù)框架是Qt Mobility 1.0.2版本推出的,一個(gè)服務(wù)(service)是一個(gè)獨(dú)立的組件提供給客戶(hù)端(client)定義好的操作。客戶(hù)端可以通過(guò)服務(wù)的名稱(chēng),版本號(hào)和服務(wù)的對(duì)象提供的接口來(lái)查找服務(wù)。 查找到服務(wù)后,框架啟動(dòng)服務(wù)并返回一個(gè)指針。
服務(wù)通過(guò)插件(plug-ins)來(lái)實(shí)現(xiàn)。為了避免客戶(hù)端依賴(lài)某個(gè)具體的庫(kù),服務(wù)必須繼承自QObject。這樣 QMetaObject 系統(tǒng)可以用來(lái)提供動(dòng)態(tài)發(fā)現(xiàn)和喚醒服務(wù)的能力。要使QmetaObject機(jī)制充分的工作,服務(wù)必須滿(mǎn)足,其所有的方法都是通過(guò) signal,slot,property 或 invokable method 和 Q_INVOKEBLE 來(lái)實(shí)現(xiàn)
其中,最常見(jiàn)的與servicer交互的方法如下:
- QServiceManagermanager;QObject*storage;
- storage=manager.loadInterface( "com.nokia.qt.examples.FileStorage" ); if (storage)QMetaObject::invokeMethod(storage, "deleteFile" ,Q_ARG(QString, "/tmp/readme.txt" ));
上面的代碼通過(guò)service的元對(duì)象提供的invokeMethod方法,調(diào)用文件存儲(chǔ)對(duì)象的deleteFile() 方法。客戶(hù)端不需要知道對(duì)象的類(lèi)型,因此也沒(méi)有鏈接到具體的service庫(kù)。 當(dāng)然在服務(wù)端的deleteFile方法,一定要被標(biāo)記為 Q_INVOKEBLE, 才能夠被元對(duì)象系統(tǒng)識(shí)別
Qt服務(wù)框架的一個(gè)亮點(diǎn)是它支持 跨進(jìn)程通信 ,服務(wù)可以接受遠(yuǎn)程進(jìn)程。在服務(wù)管理器上注冊(cè)后 進(jìn)程通過(guò)signal,slot, invokable method 和property來(lái)通信,就像本地對(duì)象一樣。服務(wù)可以設(shè)定為在客戶(hù)端間共享,或針對(duì)一個(gè)客戶(hù)端。 請(qǐng)注意 ,在Qt服務(wù)框架推出之前,信號(hào)、槽以及invokable method僅支持跨線程。 下圖是跨進(jìn)成的服務(wù)/客戶(hù)段通信示意圖(圖片來(lái)自諾基亞論壇)。這里我們可以清楚的看到, invokable method 和 Q_INVOKEBLE 是跨進(jìn)城、跨線程對(duì)象之間通信的重要利器。
有關(guān)Qt Service Framework的更多討論和用例,請(qǐng)參見(jiàn) Qt Service Framework文檔
請(qǐng)尊重原創(chuàng)作品和譯文。轉(zhuǎn)載請(qǐng)保持文章完整性,并以超鏈接形式注明原始作者
地址
http://blog.csdn.net/changsheng230
,方便其他朋友提問(wèn)和指正。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
