Machen QList<QObject*> C++ dynamische Modell in QML

Ich habe eine QList<QObject*> C++ – Modell mit benutzerdefinierten Objekte und ausgesetzt QML.

Mein benutzerdefiniertes Objekt sieht wie folgt aus:

class CustomObject : public QObject
{
  Q_OBJECT

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

    [...]

}

Mein Modell ausgesetzt ist, QML, wie diese:

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

So weit So gut. Ich kann eine Ansicht, Anzeige, alle meine Elemente und rekursiv auch Ihre Kinder.

Das problem ist, dass QList hat keine Möglichkeit, sich zu informieren, QML, dass das Modell geändert. Wie bereits in der Dokumentation über die QObjectList-basierten Modell:

Hinweis: Es gibt keine Möglichkeit für die Ansicht, zu wissen, dass der Inhalt einer
QList hat sich geändert. Wenn der QList ändert, ist es notwendig, reset der
Modell durch den Aufruf QQmlContext::setContextProperty() wieder.

Jedes mal also, wenn ich einen Artikel hinzufügen oder entfernen, rufe ich:

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

Und das ist extrem langsam.

Wenn ich das richtig verstanden habe, muss ich zu verwenden QAbstractItemModel statt.

So, ist es möglich, die Migration von QList<QObject*> zu QAbstractItemModel ohne änderung der QML Teil? In allem, sollte ich alles migrieren Q_PROPERTY aus CustomObject zu Rollen oder kann Sie „wiederverwenden“?

  • Ich habe nicht gearbeitet mit QML. Aber die Migration der Qlist in einem Modell ist einfach. es ist auch QAbstractListModel die Sie verwenden sollten. Sie haben einige Dinge geändert, obwohl wahrscheinlich, weil die Liste ausgeblendet werden soll, von der QML und nur den Zugriff durch das Modell. Aber ich denke, Qt hat einige triviale system zu setzen, das Modell einer QML-Liste anzeigen. Scheint wie ein standard-Anwendungsfall. Auch: alle spezifischen Grund, warum Sie eine Liste verwenden, und nicht ein Vektor?
  • Sie haben eine QList<QObject*> wenn Sie wollen verwenden Sie es als ein Modell in QML.
  • Die Sache ist die. Sie wirklich wollen, zu einem „Modell“ – Klasse als Modell und haben die Container versteckt in dem Modell (dann können Sie verwenden, was Sie wollen). Sie haben probalby schon gesehen, aber hier ist ein Beispiel mit einer model-Klasse: doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html weiter unten in der Dokumentation.
InformationsquelleAutor Korchkidu | 2016-09-08



One Reply
  1. 6

    Ja, das ist möglich, Sie brauchen nur zu ändern, QML leicht

    C++ model-Klasse

    #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;
    };

    Es funktioniert mit jedem Typen, die Erben von QObject. Können Sie einfügen und entfernen von Elementen mithilfe insert() und remove() die Werke sowohl von C++ und QML. Die Umsetzung ist ziemlich einfach

    #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;
    }

    Beachten Sie die Verwendung von roleNames() und "item" Rolle. Wir verwenden es in QML. Sie müssen nicht migrieren Sie Ihre CustomObject Eigenschaften zu Rollen, nur mit der einzigen Rolle und zurück QObject* Zeiger von Model::data().

    Registrierung als Model

    Model internalModel;
    qmlEngine->rootContext()->setContextProperty("internalModel", &internalModel);

    Schließlich

    ListView {
      model: internalModel
      delegate: Text {
        text: model.item.name
      }
    }

    Das einzige, was Sie tun müssen, in Ihrem QML ist ersetzen name und getChildren mit model.item.name und model.item.getChildren. Klingt einfach?

    • Ich nicht sogar denken über etwas, einfach. Das ist großartig, vielen Dank!
    • Haben Sie eine Idee, warum so ein Modell ist nicht enthalten in Qt direkt? Es scheint also nützlich. Ist es ein problem mit ihm, z.B. in Bezug auf die Speicherverwaltung? stackoverflow.com/q/43809751

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.