Qt移动应用开发:QML与C++的交互

Qt移动应用开发: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++的变量。代码如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <QApplication>  
  2. #include <QQmlApplicationEngine>  
  3. #include <QQmlContext>  
  4.   
  5. int main(int argc, char *argv[])  
  6. {  
  7.     QApplication app(argc, argv);  
  8.   
  9.     QQmlApplicationEngine engine;  
  10.     engine.rootContext( )->setContextProperty(  
  11.                 "Greeting",  
  12.                 QObject::tr( "Hello QML from C++" ) );  
  13.     engine.load(QUrl(QStringLiteral("qrc:///main.qml")));  
  14.   
  15.     return app.exec();  
  16. }  
 

然后在QML中简单地调用”Greeting”变量名就可以顺利访问了。

[css]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. import QtQuick 2.2  
  2. import QtQuick.Controls 1.1  
  3.   
  4. ApplicationWindow  
  5. {  
  6.     visible: true  
  7.     width640  
  8.     height480  
  9.     title: qsTr("测试QML于C++的交互")  
  10.   
  11.     menuBar: MenuBar  
  12.     {  
  13.         Menu  
  14.         {  
  15.             title: qsTr("文件")  
  16.             MenuItem  
  17.             {  
  18.                 text: qsTr("退出")  
  19.                 onTriggered: Qt.quit( );  
  20.             }  
  21.         }  
  22.     }  
  23.   
  24.     Text  
  25.     {  
  26.         text: qsTr("本例用来测试QML和C++的交互")  
  27.         anchors.right: parent.right  
  28.         anchors.bottom: parent.bottom  
  29.     }  
  30.   
  31.     Text  
  32.     {  
  33.         text: Greeting  
  34.         anchors.centerIn: parent  
  35.     }  
  36. }  

 

演示程序的截图如下:

       本例重要的部分是QQmlContext实例指针。它通过QQmlApplicationEngine::rootContext()来获得,也可以通过QQmlApplicationEngine:: contextForObject(constQObject * object)来获得。在QQmlObject创建的时候,都会实例化一个QQmlContext,用来支持为运行环境提供的上下文属性。

       使用上下文属性可以让QML访问C++数据,那么如何使用QML来访问C++的函数呢?这里我们在C++中注册QML类或者单例来让QML来获得访问C++函数的机会。首先介绍一下如何将QML中注册C++类到QML中。首先需要定义一个C++类继承于QObject,然后这么写:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #ifndef CPLUSPLUSCLASS_H  
  2. #define CPLUSPLUSCLASS_H  
  3.   
  4. #include <QObject>  
  5.   
  6. class CPlusPlusClass: public QObject  
  7. {  
  8.     Q_OBJECT  
  9.     Q_PROPERTY( int rating READ rating )  
  10. public:  
  11.     explicit CPlusPlusClass( QObject* pParent = Q_NULLPTR ):  
  12.         QObject( pParent )  
  13.     {  
  14.         m_Rating = 5;  
  15.     }  
  16.   
  17.     Q_INVOKABLE void method( void )  
  18.     {  
  19.         qDebug( "[C++]%s is called.", __FUNCTION__ );  
  20.     }  
  21.     int rating( void ) { return m_Rating; }  
  22. private:  
  23.     int m_Rating;  
  24. };  
  25.   
  26. #endif // CPLUSPLUSCLASS_H  

然后再main.cpp中需要调用qmlRegisterType()模板函数来注册C++类到QML中,一个典型的用法如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <QApplication>  
  2. #include <QQmlApplicationEngine>  
  3. #include <QtQml>  
  4. #include "CPlusPlusClass.h"  
  5.   
  6. int main(int argc, char *argv[])  
  7. {  
  8.     QApplication app(argc, argv);  
  9.   
  10.     // 首先注册一下类  
  11.     qmlRegisterType<CPlusPlusClass>(  
  12.                 "CPlusPlus.Test",           // 统一资源标识符  
  13.                 1,                          // 主版本  
  14.                 0,                          // 次版本  
  15.                 "CPlusPlusType" );          // QML类名称  
  16.   
  17.     QQmlApplicationEngine engine;  
  18.     engine.load(QUrl(QStringLiteral("qrc:///main.qml")));  
  19.   
  20.     return app.exec();  
  21. }  
 

       最后在QML中就可以顺利地访问C++类的属性和方法了:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. import QtQuick 2.2  
  2. import QtQuick.Controls 1.1  
  3. import CPlusPlus.Test 1.0  
  4.   
  5. ApplicationWindow  
  6. {  
  7.     visible: true  
  8.     width: 640  
  9.     height: 480  
  10.     title: qsTr("测试QML于C++的交互")  
  11.   
  12.     menuBar: MenuBar  
  13.     {  
  14.         Menu  
  15.         {  
  16.             title: qsTr("文件")  
  17.             MenuItem  
  18.             {  
  19.                 text: qsTr("退出")  
  20.                 onTriggered: Qt.quit( );  
  21.             }  
  22.         }  
  23.     }  
  24.   
  25.     Text  
  26.     {  
  27.         text: qsTr("本例用来测试QML和C++的交互")  
  28.         anchors.right: parent.right  
  29.         anchors.bottom: parent.bottom  
  30.     }  
  31.   
  32.     CPlusPlusType  
  33.     {  
  34.         id: theType  
  35.     }  
  36.   
  37.     MouseArea  
  38.     {  
  39.         anchors.fill: parent  
  40.         onClicked:  
  41.         {  
  42.             console.log( "[qml] Rating is: " + theType.rating );  
  43.             theType.method( );  
  44.         }  
  45.     }  
  46. }  
 

点击窗体,控制台运行结果如下:

qml: [qml] Ratingis: 5

[C++]method iscalled.

如果不想在QML和C++环境中创建多个QObject或者说想要更加方便地访问C++的方法,那么可以考虑注册一个单例类,注册单例类和注册普通的类差不多,但也有一些显著的区别,首先建立这样一个继承于QObject的类,代码如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #ifndef CPLUSPLUSCLASS_H  
  2. #define CPLUSPLUSCLASS_H  
  3.   
  4. #include <QObject>  
  5.   
  6. class CPlusPlusClass: public QObject  
  7. {  
  8.     Q_OBJECT  
  9.     Q_PROPERTY( int rating READ rating )  
  10. public:  
  11.     explicit CPlusPlusClass( QObject* pParent = Q_NULLPTR ):  
  12.         QObject( pParent )  
  13.     {  
  14.         m_Rating = 5;  
  15.     }  
  16.   
  17.     Q_INVOKABLE void method( void )  
  18.     {  
  19.         qDebug( "[C++]%s is called.", __FUNCTION__ );  
  20.     }  
  21.     int rating( void ) { return m_Rating; }  
  22. private:  
  23.     int m_Rating;  
  24. };  
  25.   
  26. #endif // CPLUSPLUSCLASS_H  

然后关键在main.cpp中,除了调用qmlRegisterSingletonType()模板函数外,还需要写一个静态全局的注册函数。代码如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <QApplication>  
  2. #include <QQmlApplicationEngine>  
  3. #include <QtQml>  
  4. #include "CPlusPlusSingleton.h"  
  5.   
  6. // 注册单例函数  
  7. static QObject* CPlusPlusSingletonRegisterFunc(  
  8.         QQmlEngine* pQMLEngine,  
  9.         QJSEngine* pJSEngine )  
  10. {  
  11.     Q_UNUSED( pQMLEngine );  
  12.     Q_UNUSED( pJSEngine );  
  13.   
  14.     CPlusPlusSingleton* pSingleton = new CPlusPlusSingleton;  
  15.     return pSingleton;  
  16. }  
  17.   
  18. int main(int argc, char *argv[])  
  19. {  
  20.     QApplication app(argc, argv);  
  21.   
  22.     // 首先注册一下单例  
  23.     qmlRegisterSingletonType<CPlusPlusSingleton>(  
  24.                 "CPlusPlus.Test",                   // 统一资源标识符  
  25.                 1,                                  // 主版本  
  26.                 0,                                  // 次版本  
  27.                 "CPlusPlusSingleton",               // 单例名称  
  28.                 CPlusPlusSingletonRegisterFunc );   // 函数名  
  29.   
  30.     QQmlApplicationEngine engine;  
  31.     engine.load(QUrl(QStringLiteral("qrc:///main.qml")));  
  32.   
  33.     return app.exec();  
  34. }  
 

就这样,C++的部分就完成了。接下来在QML中就很简单了:

[css]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. import QtQuick 2.2  
  2. import QtQuick.Controls 1.1  
  3. import CPlusPlus.Test 1.0  
  4.   
  5. ApplicationWindow  
  6. {  
  7.     visible: true  
  8.     width640  
  9.     height480  
  10.     title: qsTr("测试QML于C++的交互")  
  11.   
  12.     menuBar: MenuBar  
  13.     {  
  14.         Menu  
  15.         {  
  16.             title: qsTr("文件")  
  17.             MenuItem  
  18.             {  
  19.                 text: qsTr("退出")  
  20.                 onTriggered: Qt.quit( );  
  21.             }  
  22.         }  
  23.     }  
  24.   
  25.     Text  
  26.     {  
  27.         text: qsTr("本例用来测试QML和C++的交互")  
  28.         anchors.right: parent.right  
  29.         anchors.bottom: parent.bottom  
  30.     }  
  31.   
  32.     MouseArea  
  33.     {  
  34.         anchors.fill: parent  
  35.         onClicked:  
  36.         {  
  37.             console.log( "[qml] Rating is: " + CPlusPlusSingleton.rating );  
  38.             CPlusPlusSingleton.method( );  
  39.         }  
  40.     }  
  41. }  
 

点击窗体,控制台结果如下:

qml: [qml] Ratingis: 5

[C++]method iscalled.

       大家可以根据需要选择是否在C++中注册QML类和注册C++单例来获得相对应的特性。

       在我的第一款独立游戏《吃药了》中,为了顺利地接入广告SDK,需要写C++代码来保证让QML能够访问到C++的函数,广告显示效果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值