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