我正在寻找一种方法,如何将大量QObjects
传递给QML作为模型,而不是使用Repeater {}
来绘制它们。该解决方案必须符合以下标准:
解决方案1。
我知道我可以使用QQmlListProperty<QObject>
。不幸的是,如果添加/删除了对象,则在Qml中刷新所有其他对象。在更复杂/更大量的物体的情况下,这是非常笨重的。
此解决方案符合2)和3)。当通过setter更新对象并调用notifyChange()时,qml会自动更新内容,并且可以在任何QObject上使用它
解决方案2.
QAbstractList,其中包含文档(http://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel)中描述的已实现角色。
此解决方案符合1)但不符合2)和3)。添加新对象并调用beginInsertRows / endInsertRows时,只能正确刷新一个项目。但是必须为每个QObject准备Model对象,并且在QObject更改时必须手动更新模型
解决方案3。
我尝试实现QAbstractListModel,它在内部保存QObjects指针列表:QList<boost::shared_ptr<AnimalObject>> m_animals;
。
未实现roleNames()
方法时,Qml根本不会通过data()
方法查询数据。所以似乎不可能使用默认的Qt::DisplayRole
角色从QAbstractList返回QObject
当使用单个角色实现roleNames()方法时,例如“object”和data()
将内部QObject作为QVariant返回,则可以从QML访问它:
QVariant AnimalModel2::data(const QModelIndex & index, int role) const {
if ( index.row() < 0 || index.row() >= m_animals.count() )
return QVariant();
auto ptrAnimal = m_animals[index.row()];
if ( role == ObjectRole )
return qVariantFromValue(ptrAnimal.get());
}
QHash<int, QByteArray> AnimalModel2::roleNames() const {
QHash<int, QByteArray> roles;
roles[ObjectRole] = "object";
return roles;
}
这就是如何从QML访问QObject
Repeater {
model: myModel
Text {
text: "[" + model.object.name + "]";
}
}
此解决方案符合所有要求。不幸的是,有必要使用model.object.property
而不是更简单的model.property
来访问此QObject。虽然这不是什么大问题,但直接对象访问会很棒。
问题:
我的问题是。这三种方法是解决这个问题的唯一方法,还是我完全错过了其他方法?
有没有什么干净的方法如何创建QObject列表,将其传递给QML,完全支持从C ++添加/删除/更新对象并直接用QML更新它们?
PS:我在这里描述了所有这些方法,因为我相信这对许多其他人都有用。我花了几个小时才弄清楚如何做到这一切。建议的解决方案1.
正如@Velkan建议的那样,可以使用QMetaObject::property
和QMetaObject::propertyCount
动态扩展对象属性的QAbstractListModel。不幸的是,这意味着通过QDynamicPropertyChangeEvent
信号实现每个对象/属性的单独刷新。
不幸的是,对于大量的对象和属性,这种解决方案可能效率很低。对于对此解决方案感兴趣的任何人,这里有一个QMetaObject::property
测试代码段:
QVariant AnimalModel4::data(const QModelIndex & index, int role) const {
if ( index.row() < 0 || index.row() >= m_animals.count() )
return QVariant();
auto ptrAnimal = m_animals[index.row()];
const QMetaObject * pMeta = ptrAnimal->metaObject();
int propertyNo= role - (Qt::UserRole + 1);
QMetaProperty propMeta = pMeta->property(propertyNo);
QVariant value = propMeta.read(ptrAnimal.get());
return value;
}
QHash<int, QByteArray> AnimalModel4::roleNames() const {
QHash<int, QByteArray> roles;
if ( m_animals.size() == 0 )
return roles;
int role= Qt::UserRole + 1;
const QMetaObject * pMeta = m_animals.front()->metaObject();
for ( int propertyNo= 0; propertyNo< pMeta->propertyCount(); propertyNo++ )
{
QMetaProperty propMeta = pMeta->property(propertyNo);
roles[role++] = propMeta.name();
}
return roles;
}
答案 0 :(得分:0)
此解决方案符合所有要求。不幸的是,它是必要的 使用model.object.property访问此QObject而不是更多 直截了当的model.property。虽然这不是什么大不了的事,但是 很高兴有直接对象访问。
如果问题出在model.object.property
且您的解决方案较短model.property
,那么一个同样出色的解决方案是object.property
,它完全正常。您可以直接在委托对象中使用roleName
。
至于通用列表/模型类,我已经在that other question中解决了这个问题。