Qt C++属性类型提供给 QML调用(三)

前言

前面两篇文章已经介绍了 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)

我用第一个构造函数的方式一直报错,然而使用所有参数的形式就正常,目前还不知道是什么原因,先这样吧。

代码在这里

猜你喜欢

转载自blog.csdn.net/luoyayun361/article/details/80474891
今日推荐