gpt4 book ai didi

c++ - 将 QObject 列表传递给 QML 上下文的可能方法有哪些?

转载 作者:太空狗 更新时间:2023-10-29 23:14:11 26 4
gpt4 key购买 nike

我正在寻找一种方法来传递更多的 QObjects以 QML 作为模型,然后使用 Repeater {}画他们。此解决方案必须满足以下条件:

  1. 当有新对象加入列表时,只刷新此项
  2. 当任何传递的对象发生变化时,Qml 内容必须自动刷新
  3. 列表必须是通用的,没有硬编码的属性名称

解决方案 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 改变时必须手动更新 Model

解决方案 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 访问此 QObject而不是更直接model.property .虽然这没什么大不了的,但能直接访问对象就好了。

问题:

我的问题是。这三种方法是解决此问题的唯一可能方法,还是我完全错过了其他任何方法?

有没有什么干净的方法可以创建 QObject 列表,将其传递给 QML,完全支持从 C++ 添加/删除/更新对象,并直接在 QML 中更新它们?

PS:我在这里描述了所有这些方法,因为我相信这对其他许多人都有用。我花了几个小时才弄清楚如何完成所有这些。

编辑

建议的解决方案 1。

正如@Velkan 所建议的,可以使用 QMetaObject::propertyQMetaObject::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;
}

最佳答案

This solution meets all requirements. Unfortunately it's necessary to access this QObject with model.object.property instead of more straightforward model.property. Although it's not a big deal, would be great to have direct object access.

如果您的问题出在 model.object.property 上,而您的解决方案是更短的 model.property,那么同样好的解决方案是 object.property 这是完全正常的。您可以在委托(delegate)对象中直接使用 roleName

至于通用列表/模型类,我已经在 that other question 中解决了这个问题.

关于c++ - 将 QObject 列表传递给 QML 上下文的可能方法有哪些?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35065627/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com