本文介绍了使QList< QObject *>QML中的C ++模型动态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 QList< QObject *> C ++模型,其中包含自定义对象并公开给QML.

I have a QList<QObject*> C++ model containing custom objects and exposed to QML.

我的自定义对象如下:

class CustomObject : public QObject
{
  Q_OBJECT

    Q_PROPERTY(QString name READ getName NOTIFY nameChanged)
    Q_PROPERTY(QQmlListProperty<CustomObject READ getChildren NOTIFY childrenChanged)

    [...]

}

我的模型像这样暴露于QML:

My model is exposed to QML like this:

qmlEngine->rootContext()->setContextProperty("internalModel", QVariant::fromValue(m_internalModel));

到目前为止,一切都很好.我可以使用一个视图,显示所有元素,并递归显示其子元素.

So far so good. I can use a view, display all my elements and recursively also display their children.

问题在于QList无法通知QML模型已更改.如有关 基于QObjectList的模型的文档所述:

The problem is that QList has no way to notify QML that the model changed. As noted in the documentation about QObjectList-based model:

因此,每次我添加或删除项目时,我都会致电:

So everytime I add or remove an item, I call:

qmlEngine->rootContext()->setContextProperty("internalModel", QVariant::fromValue(m_internalModel));

这非常慢.

如果我理解正确,则需要改用 QAbstractItemModel .

If I understood correctly, I need to use QAbstractItemModel instead.

因此,可以在不更改QML部分的情况下从 QList< QObject *> 迁移到 QAbstractItemModel 吗?特别是,我应该将所有 Q_PROPERTY 从CustomObject迁移到角色还是可以重用"它们?

So, is it possible to migrate from QList<QObject*> to QAbstractItemModel without changing the QML part? In particular, should I migrate all Q_PROPERTY from CustomObject to roles or can "reuse them"?

推荐答案

是可以的,您只需要稍微更改QML

Yes this is possible, you only need to change QML slightly

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中都可以使用.实现非常简单

It will work with any types that inherit from QObject. You can insert and remove items by using insert() and remove() which works both from C++ and QML. The implementation is pretty simple

#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 属性迁移到角色,只需使用单个角色并从 Model :: data()返回 QObject * 指针

Note the use of roleNames() and "item" role. We will use it in QML. You do not need to migrate your CustomObject properties to roles, just use the single role and return QObject* pointer from 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 .听起来很简单?

The only thing you need to do in your QML is replace name and getChildren with model.item.name and model.item.getChildren. Sounds simple?

这篇关于使QList&lt; QObject *&gt;QML中的C ++模型动态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-29 02:12
查看更多