C++与QML混合编程技术(传递自定义数据类型)

目录

一、前言

二、C++与QML集成的基础

2.1 语言特征

2.2 可集成的前提条件

2.3 基础数据类型

2.4 自定义数据类型

三、实例讲解

3.1 QML获取C++类的自定义结构体数据

3.1.1 结构体类型

3.1.2 配置数据类

3.1.3 配置信息管理类

3.1.4 向QML元对象系统注册自定义类

3.1.5 QML调用C++函数后得到自定义结构体数据

 3.2 C++类接收QML传递的自定义数据

3.2.1 传递QML数组保存自定义数据

3.2.2 C++类解析QML数组数据

总结


一、前言

      界面代码与逻辑代码分离困扰过许多软件开发人员,使用C++与QML混合编程在一定程序上解决上这个问题,但由于它们之间的数据类型不完全兼容,对于一些复杂数据的传递(例如:结构体数据),则需要重点关注和解决,本文结合自己的实践经验分享出解决方案。

二、C++与QML集成的基础

2.1 语言特征

 C++的三个主要特征: 

  1. 封装;
  2. 继承;
  3. 多态;

 QML的两个主要特征:

  1. 描述用户界面的一种陈述性语言;
  2. 支持javacript形式的编程控制;

2.2 可集成的前提条件

 Qt元对象系统是Qt 类库独有的功能,是Qt对标准C++的扩展,它提供了三个功能:

  1. 对象之间通信机制(信号与槽);
  2. 运行时类型信息;
  3. 动态属性;

实现元对象,要满足三个条件:

  1. 该类必须继承自QObject类;
  2. 类的私有区域声明Q_OBJECT宏,用于启动元对象特性,使用动态特性,信号和槽;
  3. 元对象编译器(moc)为每个QObject子类,提供了实现元对象特性必须的代码 ;

由于QML引擎与Qt元对象系统的集成,可以从QML中访问任何从QObject继承的类的属性、方法和信号,C++代码既可以在应用中集成,也可以在插件中集成。

QML访问C++数据主要有三种方法:

  1. 将C++ 类的属性暴露给QML;
  2. 从C++ 定义QML类型;
  3. 用Context属性在QML中嵌入C++对象;

2.3 基础数据类型

C++和QML能自动转化部分常用的基础数据类型大约有16种,清单如下:

QTQML
boolbool
unsigned int, intint
doubledouble
float, qrealreal
QStringstring
QUrlurl
QColorcolor
QFontfont
QDateTimedate
QPoint, QPointFpoint
QSize, QSizeFsize
QRect, QRectFrect
QMatrix4x4matrix4x4
QQuaternionquaternion
QVector2D, QVector3D, QVector4Dvector2d, vector3d, vector4d
Q_ENUM() 或 Q_ENUMS()enumeration

2.4 自定义数据类型

16种基础数据类型以外的其它数据类型是QML所无法识别的,可将它定义为复杂数据类型,结构体数据类型属于复杂数据类型中的一种。由于QObject子类都可以注册为QML对象类型,所以构造结构体对应的自定义类来与QML交互是可行的。

三、实例讲解

本人参与的开源项目iCupBox就应用了C++与QML混合编程,使用自定义结构体数据来代表配置信息项,通过自定义结构体数据的传递,实现数据配置的加载和保存。

3.1 QML获取C++类的自定义结构体数据

3.1.1 结构体类型

根据喝水提醒功能业务的需求,分析得到要配置的自定义结构体“ST_CFG_WATER_CLOCK”。

typedef struct ST_CFG_WATER_CLOCK {
    int nWaitingInterval;
    int nReminderTimes;
    int nTwinkle;

    ST_CFG_BASIC() {
        nWaitingInterval = 0;
        nReminderTimes = 0;
        nTwinkle = 0;
    }
}CFG_WATER_CLOCK;

3.1.2 配置数据类

 声明喝水提醒功能类(config_ini.h文件)

设置Q_PROPERTY宏,C++中的变量与QML的属性建立绑定。

class WaterClock : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int waitingInterval READ getWaitingInterval WRITE setWaitingInterval)
    Q_PROPERTY(int reminderTimes READ getReminderTimes WRITE setReminderTimes)
    Q_PROPERTY(int twinkle READ getTwinkle WRITE setTwinkle)

public:
    explicit WaterClock(QObject *parent = 0);
    ~WaterClock();

    int getWaitingInterval() const;
    int getReminderTimes() const;
    int getTwinkle() const;

    void setWaitingInterval(int);
    void setReminderTimes(int);
    void setTwinkle(int);

private:
    int m_nWaitingInterval;
    int m_nReminderTimes;
    int m_nTwinkle;
};

实现喝水提醒功能类(config_ini.cpp文件)

#include "config_ini.h"

WaterClock::WaterClock(QObject *parent)
{

}

WaterClock::~WaterClock()
{

}

int WaterClock::getWaitingInterval() const
{
    return m_nWaitingInterval;
}

int WaterClock::getReminderTimes() const
{
    return m_nReminderTimes;
}

int WaterClock::getTwinkle() const
{
    return m_nTwinkle;
}

void WaterClock::setWaitingInterval(int nWaitingInterval)
{
    m_nWaitingInterval = nWaitingInterval;
}

void WaterClock::setReminderTimes(int nReminderTimes)
{
    m_nReminderTimes = nReminderTimes;
}

void WaterClock::setTwinkle(int nTwinkle)
{
    m_nTwinkle = nTwinkle;
}

3.1.3 配置信息管理类

声明配置信息管理类(config_mgr.h)

设置Q_INVOKABLE宏,C++中的函数允许被QML调用。

#ifndef CONFIG_MGR_H
#define CONFIG_MGR_H

#include <QQuickItem>
#include "config_ini.h"

class ConfigMgr : public QQuickItem
{
    Q_OBJECT

public:
    explicit ConfigMgr(QQuickItem *parent = 0);
    ~ConfigMgr() override;

public:
    Q_INVOKABLE WaterClock *loadWaterClockInfo();
    Q_INVOKABLE bool saveWaterClockInfo(const QVariantList &lstWaterClock);
};

#endif // CONFIG_MGR_H

实现配置信息管理类(config_mgr.cpp)

#include "config_mgr.h"
#include <QDebug>

ConfigMgr::ConfigMgr(QQuickItem *parent):
    QQuickItem(parent)
{
    // By default, QQuickItem does not draw anything. If you subclass
    // QQuickItem to create a visual item, you will need to uncomment the
    // following line and re-implement updatePaintNode()

    // setFlag(ItemHasContents, true);

    Q_ASSERT(NULL != ConfigINI::GetInstance(this));

    qDebug() << Q_FUNC_INFO;
}

ConfigMgr::~ConfigMgr()
{
    qDebug() << Q_FUNC_INFO;
}

WaterClock *ConfigMgr::loadWaterClockInfo()
{
    qDebug() << Q_FUNC_INFO;

    // Read data from INI
    ST_CFG_WATER_CLOCK stCfgWaterClock;
    ConfigINI::GetInstance(this)->ReadIni(stCfgWaterClock);

    // Assign value from structure to object
    WaterClock *pWaterClock = new WaterClock();
    pWaterClock->setWaitingInterval(stCfgWaterClock.nWaitingInterval);
    pWaterClock->setReminderTimes(stCfgWaterClock.nReminderTimes);
    pWaterClock->setTwinkle(stCfgWaterClock.nTwinkle);

    return pWaterClock;
}

bool ConfigMgr::saveWaterClockInfo(const QVariantList &lstWaterClock)
{
    qDebug() << Q_FUNC_INFO << lstWaterClock.size();

    if(3 != lstWaterClock.size()) return false;

    // Assign value from variant to structure
    ST_CFG_WATER_CLOCK stCfgWaterClock;
    stCfgWaterClock.nWaitingInterval = lstWaterClock[0].toInt();
    stCfgWaterClock.nReminderTimes = lstWaterClock[1].toInt();
    stCfgWaterClock.nTwinkle = lstWaterClock[2].toInt();

    // Write data into INI
    ConfigINI::GetInstance(this)->WriteIni(stCfgWaterClock);

    return true;
}

3.1.4 向QML元对象系统注册自定义类

使用qmlRegisterType,将自定义的QObject派生类注册到QML,它是连接C++和QML的工具。

#include "ipluginsmgr_plugin.h"
#include "config/config_mgr.h"

#include <qqml.h>

void IPluginsMgrPlugin::registerTypes(const char *uri)
{
    // @uri com.mycompany.qmlcomponents
    // Register class types to QML
    qmlRegisterType<WaterClock>(uri, 1, 0, "WaterClock");
    qmlRegisterType<ConfigMgr>(uri, 1, 0, "ConfigMgr");
}

3.1.5 QML调用C++函数后得到自定义结构体数据

QML及C++插件项目的文件分布如下:

main.qml文件

import QtQuick 2.5
import QtQuick.Window 2.2
import com.mycompany.qmlcomponents 1.0

Window {
    id: wndRoot

    visible: true
    width: 1000
    height: 800
    title: qsTr("iCupBox v1.0.0")

    MainForm {
        anchors.fill: parent
    }

    ConfigMgr {
        id: cppConfigMgr
    }
}

 WaterClockView.qml文件

Component.onCompleted: {
            // Load default parameter data
            var pWaterClock = cppConfigMgr.loadWaterClockInfo()
            console.log("cmb_waiting_time::onCompleted " + pWaterClock.waitingInterval, pWaterClock.reminderTimes, pWaterClock.twinkle)

            cmb_waiting_time.currentIndex = pWaterClock.waitingInterval;
            cmb_reminder_times.currentIndex = pWaterClock.reminderTimes;
            cmb_twinkle.currentIndex = pWaterClock.twinkle;
        }

 3.2 C++类接收QML传递的自定义数据

3.2.1 传递QML数组保存自定义数据

在QML中的使用信号-槽来收集页面上的配置信息数据后,使用var数据的形式暂时存储,再将其传递给C++类。

import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4

Item {
    signal currentIndexChanged()

    function onHandleCurrentIndexChanged() {
        // Get the change value of the index
        var arrWaterClock = []
        arrWaterClock.push(cmb_waiting_time.currentIndex)
        arrWaterClock.push(cmb_reminder_times.currentIndex)
        arrWaterClock.push(cmb_twinkle.currentIndex)

        // Modify default parameter data
        var result = cppConfigMgr.saveWaterClockInfo(arrWaterClock)
        console.log("onHandleUpdateWaterClock ", result)
    }

    ...

    ComboBox {
            id: cmb_waiting_time
            height: 25
            Layout.minimumWidth: 100
            model:[qsTr("25 minutes"), qsTr("50 minutes"), qsTr("75 minutes"), qsTr("100 minutes")]

            Component.onCompleted: {
                currentIndexChanged.connect(onHandleCurrentIndexChanged)
            }

            onActivated: {
                currentIndex = index
                console.log("cmb_waiting_time::onActivated", currentIndex)

                // The index is changed, and the default configuration is updated
                currentIndexChanged()
            }
        }
}

3.2.2 C++类解析QML数组数据

在config_mgr.cpp类中处理QML数据。

bool ConfigMgr::saveWaterClockInfo(const QVariantList &lstWaterClock)
{
    qDebug() << Q_FUNC_INFO << lstWaterClock.size();

    if(3 != lstWaterClock.size()) return false;

    // Assign value from variant to structure
    ST_CFG_WATER_CLOCK stCfgWaterClock;
    stCfgWaterClock.nWaitingInterval = lstWaterClock[0].toInt();
    stCfgWaterClock.nReminderTimes = lstWaterClock[1].toInt();
    stCfgWaterClock.nTwinkle = lstWaterClock[2].toInt();

    // Write data into INI
    ConfigINI::GetInstance(this)->WriteIni(stCfgWaterClock);

    return true;
}

总结

C++与QML混合编程就是优势互补的编程策略,使用QML高效便捷地构建UI,使用C++实现业务逻辑和复杂算法。

  • 6
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: QMLQt Meta-Object Language)是一种用于构建用户界面的声明性语言,而C/C++是一种通用的编程语言。QML与C混合编程是使用这两种语言结合开发应用程序的一种方式。 在QML中,可以使用JavaScript进行逻辑编程和交互操作。而在C/C++中,可以进行复杂的计算、算法实现和底层操作。通过将这两种语言结合在一起,可以充分发挥它们各自的优势,提高应用程序的开发效率和性能。 使用QML与C混合编程时,通常会有一些场景需要注意。首先,需要在C/C++中编写一些类或者函数,然后在QML中进行调用。这就需要进行跨语言的接口和数据传递。通常可以使用Qt提供的机制,如信号与槽(signal and slot)来进行跨语言的通信。 其次,在QML中可以使用Qt的各种GUI组件来构建用户界面,而在C/C++中则可以处理一些底层的计算和数据操作。例如,可以在C/C++中使用Qt的数据结构和算法来处理复杂的数据逻辑,然后将结果传递QML进行展示。 混合编程还可以提高应用程序的性能。QML中的JavaScript运行速度相对较慢,而C/C++则可以通过编译优化和底层操作来提高执行效率。因此,在一些对性能要求较高的场景下,可以将一些计算密集型的任务交给C/C++来处理,提高整体应用程序的性能。 总结来说,QML与C混合编程可以充分发挥两种语言各自的优势,提高应用程序的开发效率、性能和用户体验。通过合理地利用QML和C/C++,可以开发出功能强大、界面美观且性能优异的应用程序。 ### 回答2: QMLQt Meta-Object Language)是一种用于快速构建用户界面的声明性编程语言,而C++是一种通用的编程语言。两者结合进行混合编程可以充分发挥各自的优势。 首先,QML具有直观易懂的语法,适合快速开发用户界面。它采用了类似于CSS的声明式风格,允许开发者通过组件和属性的方式构建用户交互界面。QML中可以直接调用C++函数和对象,并通过信号槽机制进行通信,这使得在QML中可以方便地使用C++的功能和库。 其次,C++是一种强大的编程语言,具有高效的性能和广泛的应用领域。通过与QML混合编程,我们可以利用C++的能力来处理复杂的业务逻辑和计算任务。例如,使用C++编写性能要求较高的算法,通过C++的多线程处理并发任务等。 混合编程可以通过QML中的Qt Quick Controls提供更丰富的用户界面控件和样式,通过C++编写的QML插件来实现一些复杂的界面逻辑或业务逻辑。这种结合可以在保持界面的灵活性和用户友好性的同时,实现高效的数据处理和计算。 总结来说,QMLC++混合编程方式可以在开发过程中充分利用两者的优势,快速构建用户界面并处理复杂的业务逻辑。这种结合使得开发人员能够更有效地开发出高性能、用户友好的应用程序。 ### 回答3: qml与C混合编程是指在Qt框架中,同时使用qml和C语言进行开发的一种方式。qmlQt Quick的一种声明式语言,用于快速构建用户界面,而C语言是一种通用的编程语言,在Qt中常用于底层功能的实现。 qml与C混合编程的主要优点是可以充分利用qml的快速开发和灵活性和C语言的强大功能。qml具有直观的语法和简洁的代码风格,能够快速构建出美观且交互性强的用户界面。同时,qml也具有与C++进行无缝集成的能力,可以调用C++类和函数来实现一些高级的功能。而C语言作为一种通用的编程语言,具有底层的硬件控制和高性能的特点,适合用于一些需要高效计算和硬件交互的场景。通过qml与C混合编程,可以实现高效的用户界面和底层功能的结合,提供优秀的用户体验和性能。 在qml与C混合编程时,一般会使用Qt提供的接口和工具来实现qml与C语言的交互。Qt提供了QCoreApplication类和QObject类等接口,用于qml与C语言之间的通信和数据传递。可以通过qml提供的信号与槽机制,与C语言进行交互和传递数据。在qml中,可以调用C语言的函数来实现一些底层操作,比如文件读写、网络通信等。而在C语言中,可以通过Qt提供的接口,调用qml中的函数和属性,实现界面的更新和事件的处理。 总之,qml与C混合编程是一种灵活且强大的开发方式,可以充分发挥qml的优势和C语言的功能,实现高效的用户界面和底层功能的结合。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值