在QML中使QList <qobject *> C ++模型动态化

时间:2016-09-08 08:59:39

标签: c++ qt qml

我有一个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迁移到角色还是可以“重用它们”?

1 个答案:

答案 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中唯一需要做的就是用namegetChildren替换model.item.namemodel.item.getChildren。听起来很简单?