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++的变量。代码如下:


#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.2
import QtQuick.Controls 1.1

ApplicationWindow
{
    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.2
import QtQuick.Controls 1.1
import CPlusPlus.Test 1.0

ApplicationWindow
{
    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.2
import QtQuick.Controls 1.1
import CPlusPlus.Test 1.0

ApplicationWindow
{
    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博文大赛,请大家支持我,为我投一票!

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

时间: 2024-11-07 02:26:28

Qt移动应用开发(六):QML与C++的交互的相关文章

Qt移动应用开发(六):QML与C++互动

Qt移动应用开发(六):QML与C++互动 上一篇文章讲到了在Qt Quick中实现场景切换的一种可能的方法,场景切换是诸如游戏等应用在内必需要面临的技术难点,所以场景切换并没有通行的方法,依据自己的使用习惯进行设计就可以. 本文主要介绍的是怎样使用QML和C++进行交互,难度略微偏大,适合有经验的Qt开发人员进行学习交流. Qt 5吸收了Qt 4的declarative模块的长处,对底层进行了更改,新建了QPA层,隔离了不同操作系统API和上层Qt代码.同一时候QML/QtQuick也能够顺利

Qt移动应用开发(八):实现跨平台的QML和OpenGL混合渲染

上一篇文章讲到了利用C++这个桥梁,我们实现了QML和Java的交互.Qt 5大力推崇的QML/JS开发,让轻量.快速开发的QML/JS打头阵,让重量的C++撑腰,几乎什么技术都能够实现.接下来的这篇文章讲的是我们使用QML,借助Qt库和OpenGL,实现了使用着色器定义OpenGL的渲染方式,为大家呈现混合渲染的效果. 原创文章,反对未声明的引用.原博客地址:http://blog.csdn.net/gamesdev/article/details/38024327 本文难度偏大,适合有经验的

Qt移动应用开发(七):QML与Java的交互

上一篇文章讲到了如何实现QML和C++的交互,QML和C++的交互方法有很多,它们分别为使用上下文变量.注册QML类以及注册QML单例.那么这一次我们要了解如何使QML和Java进行交互.这里主要讲的是在Android系统下的实现,不适用于桌面平台J2SE的JVM. 原创文章,反对未声明的引用.原博客地址:http://blog.csdn.net/gamesdev/article/details/37997555 Qt5中针对不同的平台适配并开发了不同的模块,比如说Qt Windows Extr

Qt for Android 开发大坑

Qt for Android 开发大坑 作者: qyvlik Qt 5.5.1 这里说一说比较常见的 Qt 开发安卓的大坑.希望同学们不要做无谓的挣扎,跳过这些坑. 输入框 首当其冲的是输入框,Qt 的输入在安卓上表现不佳. 无法支持安卓原生的输入法访问 Qt 的输入框,就是安卓输入法无法复制,粘贴,剪切 Qt 输入框中的文本. 无法支持使用触摸的方式选中 Qt 输入框中的文字. 如果输入框的位置处于应用底部,类似于 IM 那种聊天工具,应当注意. a. 如果应用 Activity 设置为 an

Qt移动应用开发(一):适配不同的屏幕

Qt移动应用开发(一):适配不同的屏幕 到目前为止,Qt5.3已经出现很长一段时间了,并且已经有一些应用使用Qt进行构建了,我自己也完成了第一款使用Qt构建的手机游戏<吃药了>.那么接下来的几篇文章主要向大家分享我是怎样使用Qt进行移动开发的.Qt移动应用开发分为多篇博客文章,每一篇文章都力求精简不罗嗦,力求为大家提供一个快捷的参考.我在这里也主要将使用Qt制作<吃药了>的方法技巧一一分享给大家. 说到移动应用开发,第一想到的就是Android了,的确.Digia其实在为Qt制定向

Qt Quick应用开发介绍 1-5

Qt Quick应用开发介绍 Introduction to Application Development with Qt Quick Release 1.0 Chapter1 Introduction 介绍 1.1 谁应该阅读这份教程 本教程解释了Qt Quick应用开发的基础以及使用示例代码帮助全面了解; 教程包含标准Qt Quick文档和基础概念, API以及详细的源码信息; 本教程是为了新接触Qt Quick的你准备的, 虽然从基础开始, 但你还是要熟悉编程的概念, 有JavaScri

Qt移动应用开发(五):场景切换

上篇文章讲到了如何用QtQuick实现绚丽的粒子特效.粒子特效的出现可以说给了开发人员一个个性化界面开发的一个契机,以后可以创造出更多有趣的界面出来,并适配到Android.iOS等移动平台上,从而让你的程序变得更加有趣! 原创文章,反对未声明的引用.原博客地址:http://blog.csdn.net/gamesdev/article/details/34840415 这一次我将介绍我在实际应用开发的时候是如何实现场景的切换的.场景的切换问题是一个架构上的问题,有很多的实现方式,而Qt Qui

Qt移动应用开发(二):使用动画框架

上一篇博客介绍了如何使用Qt的QML来对屏幕分辨率大小进行适应,事实上,不同分辨率的适应是一个非常棘手的问题,除了分辨率不同外,宽高比(aspect ratio)也不尽相同.有些平板在硬件上做得和IPad一样是Retina屏(2048×1536),有些低端的手机分辨率只有320×480,这样宽高比又不一样了,所以在设计App的过程一定要对内容布局有所规划.采用锚布局的方法可以帮我们解决一定的问题,同时也要善用Screen类的成员来获得系统分辨率的更多信息. 这篇文章主要介绍的是QtQuick的动

Qt Quick应用开发介绍 9

Chapter9 Interactive UI with Multiple Top-Level Windows 多个顶层窗口下的交互式UI 现在我们的程序需要添加一些方法来变得适合日常工作中的重用; 首先要有个button来退出; 其次, 要有top-level窗口来管理配置; 用户修改配置时, 程序应该检查变动, 让用户知道改动是否正确; 9.1 A Button button用来退出程序, 打开窗口, 关闭窗口等; button应该有基本的可视化参数, 并且在点击时发送信号; button在