我有一个QList<QObject*>
C ++模型,其中包含自定义对象并向QML公开。
我的自定义对象如下所示:
class CustomObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ getName NOTIFY nameChanged)
Q_PROPERTY(QQmlListProperty<CustomObject READ getChildren NOTIFY childrenChanged)
[...]
}
我的模型接触到QML,如下所示:
qmlEngine->rootContext()->setContextProperty("internalModel", QVariant::fromValue(m_internalModel));
到目前为止一切顺利。我可以使用一个视图,显示我的所有元素,并递归地显示他们的孩子。
问题是QList无法通知QML模型已更改。正如有关 QObjectList-based model 的文档中所述:
注意:视图无法知道a的内容 QList已经改变。如果QList发生变化,则需要重置 通过再次调用QQmlContext :: setContextProperty()模型。
所以每当我添加或删除一个项目时,我都会打电话:
qmlEngine->rootContext()->setContextProperty("internalModel", QVariant::fromValue(m_internalModel));
这非常慢。
如果我理解正确,我需要改为使用QAbstractItemModel
。
那么,是否可以在不更改QML部分的情况下从QList<QObject*>
迁移到QAbstractItemModel
?特别是,我应该将所有Q_PROPERTY
从CustomObject迁移到角色还是可以“重用它们”?
答案 0 :(得分:6)
是的,这是可能的,你只需稍微改变QML
C ++模型类
#pragma once
#include <QAbstractListModel>
#include <QVector>
class Model : public QAbstractListModel {
Q_OBJECT
public:
int rowCount(const QModelIndex&) const override;
QVariant data(const QModelIndex& index, int role) const override;
public slots:
void insert(QObject* item);
void remove(QObject* item);
protected:
QHash<int, QByteArray> roleNames() const override;
private:
QVector<QObject*> mItems;
};
它适用于从QObject
继承的任何类型。您可以使用insert()
和remove()
插入和删除项目,这些项目都适用于C ++和QML。实现非常简单
#include "model.h"
int Model::rowCount(const QModelIndex&) const {
return mItems.size();
}
QVariant Model::data(const QModelIndex& index, int /*role*/) const {
QObject* item = mItems.at(index.row());
return QVariant::fromValue(item);
}
void Model::insert(QObject* item) {
beginInsertRows(QModelIndex(), 0, 0);
mItems.push_front(item);
endInsertRows();
}
void Model::remove(QObject* item) {
for (int i = 0; i < mItems.size(); ++i) {
if (mItems.at(i) == item) {
beginRemoveRows(QModelIndex(), i, i);
mItems.remove(i);
endRemoveRows();
break;
}
}
}
QHash<int, QByteArray> Model::roleNames() const {
QHash<int, QByteArray> roles;
roles[Qt::UserRole + 1] = "item";
return roles;
}
请注意roleNames()
和"item"
角色的使用。我们将在QML中使用它。您无需将CustomObject
属性迁移到角色,只需使用单个角色并从QObject*
返回Model::data()
指针。
模型注册
Model internalModel;
qmlEngine->rootContext()->setContextProperty("internalModel", &internalModel);
<强>最后强>
ListView {
model: internalModel
delegate: Text {
text: model.item.name
}
}
您在QML中唯一需要做的就是用name
和getChildren
替换model.item.name
和model.item.getChildren
。听起来很简单?