Qt 之C++与QML交互 二

本文详细介绍了如何在C++与QML之间进行数据交互,特别是枚举类型、结构体、列表和Map的转换。通过Q_ENUMS宏将C++枚举暴露给QML,使用QVariantList和QVariantMap作为QML与C++之间的桥梁,实现不同类型数据的传递。此外,还展示了QML中如何解析和使用这些数据类型。
摘要由CSDN通过智能技术生成

项目中C++与QML交互,除了基本类型之外,很多是通过Enum,QList,QMap或者Struct结构体来传递变量,但是QML是不能直接使用这些类型,下面介绍C++中使用这些类型作为返回值的函数使用。

  1. 使用枚举类型
  2. 使用结构体类型
  3. 使用列表类型
  4. 使用Map类型

先明确一点,要在 C++和 QML 中使用 list 和 map 类型,不是直接使用 QList 和 QMap,而是另外两个来替换QVariantList 和 QVariantMap,而这两个只是 QList 和 QMap 的一个重定义的别名,先来看看其定义:

typedef QVariantMap
Synonym for QMap<QString, QVariant>.

typedef QVariantList
Synonym for QList<QVariant>.

Q_ENUMS

C++的枚举类型如果要在QML中使用,需要在使用Q_ENUMS去修饰这个枚举类型。

class MyClass : public QObject
{
    Q_OBJECT
    Q_ENUMS(MyEnum)
public:
    MyClass (QObject *parent = 0);
    ~MyClass ();
 
    enum MyEnum{
        RGB,
        YUV,
        NV12
    };  
    Q_INVOKABLE MyEnum colorType() const;
    Q_INVOKABLE void setColorType(MyEnum );
private:
    MyEnum m_colortype;
};

结构体类型或Map类型

如果QML不能使用结构体,必须将结构体类型转换为QVariantMap或QVariant,关键代码如下

#include <QObject>
#include <QVariant>
#include <QVariantMap>
#include <QVariantList>

class MyDemo : public QObject
{
    Q_OBJECT
	Q_ENUMS(Gender)
public:
	enum Gender
	{
		 Boy,
		 Girl
	}
    struct PeopleInfo
    {
        int year;          	 			// 年龄
       	int course , 					//年纪
        Gender gender;        	// 性别
        QString name    		   // 名字
    };

public:
    MyDemo (QObject *parent = nullptr);
    ~MyDemo ();

    // 获取学生信息
    Q_INVOKABLE QVariantMap getCurrentStudentInfo();

private:
    // 学生信息
    PeopleInfo  m_studentInfo;
};

// 获取天气信息
QVariantMap MyDemo ::getCurrentStudentInfo(void)
{
    QVariantMap map;
    map.clear();

    map.insert("year", m_studentInfo.year);
    map.insert("course ", m_studentInfo.course );
    map.insert("gender", m_studentInfo.gender);
    map.insert("name", m_studentInfo.name);
    return map;
}

列表类型

同结构体类型相同,需要将列表转变为QVariantList类型,下面仅列出关键的代码

// 获取学生列表

Q_INVOKABLE QVariantList getStudentNameList(void);

QVariantList MyDemo ::getStudentNameList(void)
{
    QVariantList varList;
    for (int i=0; i<m_studentNameList.count(); ++i)
    {
        varList.push_back(m_studentNameList.at(i));
    }
    return varList;
}

另外附例:
先看看 QML 中的代码:

// MyItem.qml

Item {
    function readValues(anArray, anObject) {
        for (var i=0; i<anArray.length; i++)
            console.log("Array item:", anArray[i])

        for (var prop in anObject) {
            console.log("Object item:", prop, "=", anObject[prop])
        }
    }
}

接着来看 C++中的调用方法:

// C++

QQuickView view(QUrl::fromLocalFile("MyItem.qml"));

QVariantList list;
list << 10 << QColor(Qt::green) << "bottles";

QVariantMap map;
map.insert("language", "QML");
map.insert("released", QDate(2010, 9, 21));

QMetaObject::invokeMethod(view.rootObject(), "readValues",
        Q_ARG(QVariant, QVariant::fromValue(list)),
        Q_ARG(QVariant, QVariant::fromValue(map)));

C++中定义了List 和 Map 类型,并调用 QML 中的函数,并在 QML 函数中将数据打印出来。
输出结果:

Array item: 10
Array item: #00ff00
Array item: bottles
Object item: language = QML
Object item: released = Tue Sep 21 2010 00:00:00 GMT+1000 (EST)

以上示例演示了如何将 C++中的 list 和 map 类型转换到 QML 中进行使用。那么,如果要将 QML 中的这两个类型转换到 C++中使用,也是一样的用法,可以在QML中将值创建为JavaScript数组或对象,并在将值传递给C ++时自动转换为QVariantList或QVariantMap。

QVariantList以及QStringList在qml中是可以被识别的。直接通过索引,比如 mList[i] 就可以访问,但是map就不能直接访问,需要做一些处理,下面提供一种方法:
在c++中,有一个函数,返回的是QVariantList类型的返回值:

QVariantList Manager::getFlowConfiguration()
{
    QVariantList cfgList;
    QMap<int, QVariantMap> tempMap;
     ......
    for(auto key : tempMap.keys())
    {
        cfgList.push_back(tempMap[key]);
    }

    return cfgList;
}

然后再qml中可以这样子用:

ListView{
	id:root
    ......
    property ListModel myModels: ListModel{}

    function loadData()
    {
        var tempModel = manager.getFlowConfiguration()
        myModels.clear()
        
        //QVariantList的拆解
        for(var i = 0; i < tempModel.length; i++)
        {
            var count = 0;
            var data = tempModel[i];
            var dataList = []; //一个容器,用于存放json变量
            
            //QVariantMap的拆解
            for(var key in data)
            {
                dataList.push({"name":key, "state:":data[key]})
                count++
            }
            
            myModels.append({"count":count, "listData":dataList})
        }

        //改变listview的model
        model = myModels
    }
    
    delegate:Rectangle{
     Text{text:"共有" + count + "个机关"}
     Grid{
                Repeater {
                    model: listData
                    delegate:Text{text:name}
             }
    }
 .....
}

得到的结果展示如下图所示
其中步骤1、2、3那里是第一阶的listview
智能灯、智能灯一、智能灯二那里是二阶的listview(其实是Grid)。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值