Qt行動裝置 App開發(六):QML與C++的互動
Qt行動裝置 App開發(六):QML與C++的互動
上一篇文章講到了在Qt Quick中實現情境切換的一種可能的方法,情境切換是諸如遊戲等應用在內必須要面臨的技術痛點,所以情境切換並沒有通行的方法,根據自己的使用習慣進行設計即可。
本文主要介紹的是如何使用QML和C++進行互動,難度稍微偏大,適合有經驗的Qt開發人員進行學習交流。
Qt 5吸收了Qt 4的declarative模組的優點,對底層進行了更改,建立了QPA層,隔離了不同作業系統API和上層Qt代碼,同時QML/QtQuick也可以順利在不同平台上運行。另外由於考慮到讓Qt程式接入不同的庫函數,因此Qt開放了介面讓QML層和C++代碼進行互動。之前已經有較多介紹QML與C++互動的文章了,本文僅作為一種有益的補充,更多相關的知識可以查詢Qt協助文檔或向我留言。
本文的例子在Qt 5.3.1中順利編譯運行通過。
原創文章,反對未聲明的引用。原部落格地址:http://blog.csdn.net/gamesdev/article/details/37359873
首先一個較為簡單的方法就是註冊內容屬性(Context Property),讓QML訪問C++的變數。代碼如下:
#include <QApplication>#include <QQmlApplicationEngine>#include <QQmlContext>int main(int argc, char *argv[]){ QApplication app(argc, argv); QQmlApplicationEngine engine; engine.rootContext( )->setContextProperty( "Greeting", QObject::tr( "Hello QML from C++" ) ); engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); return app.exec();}
然後在QML中簡單地調用”Greeting”變數名就可以順利訪問了。
import QtQuick 2.2import QtQuick.Controls 1.1ApplicationWindow{ visible: true width: 640 height: 480 title: qsTr("測試QML於C++的互動") menuBar: MenuBar { Menu { title: qsTr("檔案") MenuItem { text: qsTr("退出") onTriggered: Qt.quit( ); } } } Text { text: qsTr("本例用來測試QML和C++的互動") anchors.right: parent.right anchors.bottom: parent.bottom } Text { text: Greeting anchors.centerIn: parent }}
示範程式的如下:
本例重要的部分是QQmlContext執行個體指標。它通過QQmlApplicationEngine::rootContext()來獲得,也可以通過QQmlApplicationEngine:: contextForObject(constQObject * object)來獲得。在QQmlObject建立的時候,都會執行個體化一個QQmlContext,用來支援為運行環境提供的內容屬性。
使用內容屬性可以讓QML訪問C++資料,那麼如何使用QML來訪問C++的函數呢?這裡我們在C++中註冊QML類或者單例來讓QML來獲得訪問C++函數的機會。首先介紹一下如何將QML中註冊C++類到QML中。首先需要定義一個C++類繼承於QObject,然後這麼寫:
#ifndef CPLUSPLUSCLASS_H#define CPLUSPLUSCLASS_H#include <QObject>class CPlusPlusClass: public QObject{ Q_OBJECT Q_PROPERTY( int rating READ rating )public: explicit CPlusPlusClass( QObject* pParent = Q_NULLPTR ): QObject( pParent ) { m_Rating = 5; } Q_INVOKABLE void method( void ) { qDebug( "[C++]%s is called.", __FUNCTION__ ); } int rating( void ) { return m_Rating; }private: int m_Rating;};#endif // CPLUSPLUSCLASS_H
然後再main.cpp中需要調用qmlRegisterType()模板函數來註冊C++類到QML中,一個典型的用法如下:
#include <QApplication>#include <QQmlApplicationEngine>#include <QtQml>#include "CPlusPlusClass.h"int main(int argc, char *argv[]){ QApplication app(argc, argv); // 首先註冊一下類 qmlRegisterType<CPlusPlusClass>( "CPlusPlus.Test", // 統一資源識別項 1, // 主要版本 0, // 次版本 "CPlusPlusType" ); // QML類名稱 QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); return app.exec();}
最後在QML中就可以順利地訪問C++類的屬性和方法了:
import QtQuick 2.2import QtQuick.Controls 1.1import CPlusPlus.Test 1.0ApplicationWindow{ visible: true width: 640 height: 480 title: qsTr("測試QML於C++的互動") menuBar: MenuBar { Menu { title: qsTr("檔案") MenuItem { text: qsTr("退出") onTriggered: Qt.quit( ); } } } Text { text: qsTr("本例用來測試QML和C++的互動") anchors.right: parent.right anchors.bottom: parent.bottom } CPlusPlusType { id: theType } MouseArea { anchors.fill: parent onClicked: { console.log( "[qml] Rating is: " + theType.rating ); theType.method( ); } }}
點擊表單,控制台運行結果如下:
qml: [qml] Ratingis: 5
[C++]method iscalled.
如果不想在QML和C++環境中建立多個QObject或者說想要更加方便地訪問C++的方法,那麼可以考慮註冊一個單例類,註冊單例類和註冊普通的類差不多,但也有一些顯著的區別,首先建立這樣一個繼承於QObject的類,代碼如下:
#ifndef CPLUSPLUSCLASS_H#define CPLUSPLUSCLASS_H#include <QObject>class CPlusPlusClass: public QObject{ Q_OBJECT Q_PROPERTY( int rating READ rating )public: explicit CPlusPlusClass( QObject* pParent = Q_NULLPTR ): QObject( pParent ) { m_Rating = 5; } Q_INVOKABLE void method( void ) { qDebug( "[C++]%s is called.", __FUNCTION__ ); } int rating( void ) { return m_Rating; }private: int m_Rating;};#endif // CPLUSPLUSCLASS_H
然後關鍵在main.cpp中,除了調用qmlRegisterSingletonType()模板函數外,還需要寫一個靜態全域的註冊函數。代碼如下:
#include <QApplication>#include <QQmlApplicationEngine>#include <QtQml>#include "CPlusPlusSingleton.h"// 註冊單例函數static QObject* CPlusPlusSingletonRegisterFunc( QQmlEngine* pQMLEngine, QJSEngine* pJSEngine ){ Q_UNUSED( pQMLEngine ); Q_UNUSED( pJSEngine ); CPlusPlusSingleton* pSingleton = new CPlusPlusSingleton; return pSingleton;}int main(int argc, char *argv[]){ QApplication app(argc, argv); // 首先註冊一下單例 qmlRegisterSingletonType<CPlusPlusSingleton>( "CPlusPlus.Test", // 統一資源識別項 1, // 主要版本 0, // 次版本 "CPlusPlusSingleton", // 單例名稱 CPlusPlusSingletonRegisterFunc ); // 函數名 QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); return app.exec();}
就這樣,C++的部分就完成了。接下來在QML中就很簡單了:
import QtQuick 2.2import QtQuick.Controls 1.1import CPlusPlus.Test 1.0ApplicationWindow{ visible: true width: 640 height: 480 title: qsTr("測試QML於C++的互動") menuBar: MenuBar { Menu { title: qsTr("檔案") MenuItem { text: qsTr("退出") onTriggered: Qt.quit( ); } } } Text { text: qsTr("本例用來測試QML和C++的互動") anchors.right: parent.right anchors.bottom: parent.bottom } MouseArea { anchors.fill: parent onClicked: { console.log( "[qml] Rating is: " + CPlusPlusSingleton.rating ); CPlusPlusSingleton.method( ); } }}
點擊表單,控制台結果如下:
qml: [qml] Ratingis: 5
[C++]method iscalled.
大家可以根據需要選擇是否在C++中註冊QML類和註冊C++單例來獲得相對應的特性。
在我的第一款獨立遊戲《吃藥了》中,為了順利地接入廣告SDK,需要寫C++代碼來保證讓QML能夠訪問到C++的函數,廣告顯示效果如下:
本文參加了CSDN博文大賽,請大家支援我,為我投一票!