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

本文介绍了C++与QML集成的基础,包括语言特征、集成前提条件和数据类型转换。通过实例详细阐述了如何在QML中获取和传递C++类的自定义结构体数据,以及C++类如何接收QML的自定义数据,展示了C++与QML混合编程在界面与逻辑分离方面的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、前言

二、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++实现业务逻辑和复杂算法。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值