前言
前面两篇文章已经介绍了 QML 中如何调用 C++中的基础属性以及对象属性,今天继续来介绍另外一种:对象为列表类型的属性调用方法。
概述
包含QObject派生类型列表的属性也可以暴露给QML使用,但是,应该使用QQmlListProperty类而不是QList< T >作为属性类型。这是因为QList不是QObject派生的类型,所以不能通过Qt元对象系统提供必要的QML属性特性,例如,当列表被修改时的信号通知,这就需要调用对象为列表类型的属性。
QQmlListProperty是一个模板类,可以通过QList值方便地构建。
正文
我们继续在之前的工程中进行修改,新建一个 School 类,示例如下:
//school.h
#include <QQmlListProperty>
#include <QObject>
#include <QDebug>
#include "student.h"
class School : public QObject
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<Student> students READ students)
public:
explicit School(QObject * parent = 0);
QQmlListProperty<Student> students();
void appendStudent(Student * stu);
int studentCount() const;
Student *student(int) const;
void clearStudent();
private:
static void appendStudent(QQmlListProperty<Student> *list, Student * s);
static int studentCount(QQmlListProperty<Student>*);
static Student* student(QQmlListProperty<Student>*, int);
static void clearStudent(QQmlListProperty<Student>*);
private:
QList<Student *> m_students;
};
//school.cpp
School::School(QObject *parent) : QObject(parent)
{
}
QQmlListProperty<Student> School::students()
{
return QQmlListProperty<Student>(this,this,
&School::appendStudent,
&School::studentCount,
&School::student,
&School::clearStudent);
}
void School::appendStudent(Student *stu)
{
m_students.append(stu);
}
int School::studentCount() const
{
return m_students.count();
}
Student *School::student(int index) const
{
return m_students.at(index);
}
void School::clearStudent()
{
return m_students.clear();
}
void School::appendStudent(QQmlListProperty<Student> *list, Student *s)
{
reinterpret_cast< School* >(list->data)->appendStudent(s);
}
int School::studentCount(QQmlListProperty<Student> *list)
{
return reinterpret_cast< School* >(list->data)->studentCount();
}
Student *School::student(QQmlListProperty<Student> *list, int i)
{
return reinterpret_cast< School* >(list->data)->student(i);
}
void School::clearStudent(QQmlListProperty<Student> *list)
{
reinterpret_cast< School* >(list->data)->clearStudent();
}
School 里面提供了一个students列表,并注册成QQmlListProperty类型供 QML 调用。
然后 Student 类保持不变:
class Student : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ getName WRITE setName NOTIFY sigNameChanged)
public:
explicit Student(QObject *parent = nullptr);
~Student(){}
void setName(const QString & name){
if(name != m_name){
m_name = name;
emit sigNameChanged(m_name);
}
}
QString getName() const {return m_name;}
signals:
void sigNameChanged(QString name);
private:
QString m_name;
};
在 Main 函数中对类进行注册:
qmlRegisterType<Student>("Student", 1, 0, "Student");
qmlRegisterType<School>("School", 1, 0, "School");
然后在 QML 中进行调用:
import QtQuick 2.8
import Student 1.0
import School 1.0
School{
students:[
Student{name:"xiaoming"},
Student{name:"zhangsan"},
Student{name:"lisi"}
]
}
这里定义了一个School类型,其中包含三个 Student,每个 Student 设置其名称。
然后我们回到 main 函数中 将 qml 定义好的对象打印出来看看效果:
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:main.qml"));
School *school = qobject_cast<School *>(component.create());
if(school){
for (int i = 0; i < school->studentCount(); ++i)
qWarning() << " " << school->student(i)->getName();
}
运行程序,输出如下:
"xiaoming"
"zhangsan"
"lisi"
本文中是试验从 QML 中创建列表对象,然后在C++中打印出创建好的列表,当然也可以在 C++中创建好列表,然后在 QML 中进行调用。使用方法都是一样,这里就不再赘述。
需要注意的是,在 Qt 帮助文档中,QQmlListProperty的使用方法如下:
class MessageBoard : public QObject
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<Message> messages READ messages)
public:
QQmlListProperty<Message> messages();
private:
static void append_message(QQmlListProperty<Message> *list, Message *msg);
QList<Message *> m_messages;
};
QQmlListProperty<Message> MessageBoard::messages()
{
return QQmlListProperty<Message>(this, 0, &MessageBoard::append_message);
}
void MessageBoard::append_message(QQmlListProperty<Message> *list, Message *msg)
{
MessageBoard *msgBoard = qobject_cast<MessageBoard *>(list->object);
if (msg)
msgBoard->m_messages.append(msg);
}
- 这里添加列表元素的时候只用到了一个静态函数append_message,奇怪的是我用这种方法一直会报错,编译不通过,无奈之下用了第二种方法,将所有需要的静态函数全部写进去了。其实该类的构造函数有三个,如下:
QQmlListProperty::QQmlListProperty(QObject *object, QList<T *> &list)
QQmlListProperty::QQmlListProperty(QObject *object, void *data, AppendFunction append, CountFunction count, AtFunction at, ClearFunction clear)
QQmlListProperty::QQmlListProperty(QObject *object, void *data, CountFunction count, AtFunction at)
我用第一个构造函数的方式一直报错,然而使用所有参数的形式就正常,目前还不知道是什么原因,先这样吧。