Nested list in qml: data models in models

I am trying to implement a nested comment system in the QML interface. I have a model in C ++ (a subclass of QAbstractListModel) in which each element in the model returns two values: one is QString and the other is QVariantMap with the role name "dataMap". This works great with QML ListView. Now each QVariantMap contains a "data" element, which further contains the "children" of the QVariantList. Now it lists mainly other QVariantMaps with the same structure. My idea to implement this is to use a recursive delegate in a QML ListView. Below is the simplest version of my code.

ListView{ id: commentsList anchors.fill: parent model: commentsModel delegate: commentsDelegate } Component{ id: commentsDelegate ColumnLayout{ Rectangle{ width: 600 height: 200 Text { id: bodyText text: dataMap.body anchors.centerIn: parent Component.onCompleted: console.debug(text) } } ListView{ id: childList property var childModel: dataMap.replies.data.children // QVariantList exposed to QML x: 15 interactive: false model: childModel anchors.fill: parent delegate: commentsDelegate } } } 

The structure of my model is as follows:

 class ListModel : public QAbstractListModel { Q_OBJECT public: ListModel(){} explicit ListModel(QObject* parent =0); ~ListModel(); QHash<int, QByteArray> roleNames() const; QVariant data(const QModelIndex & index, int role) const; int rowCount(const QModelIndex &parent) const; void addItem(ListItem item); void clearModel(); private: QList<ListItem> m_itemsList; signals: void dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight); }; 

ListItem class is simple

 class ListItem { public: ListItem(QObject* parent = 0) : QObject(parent) {} virtual ~ListItem() {} ListItem(const QString & type, const QVariantMap & dataMap); QString type() const; QVariantMap dataMap() const; private: QString m_type; QVariantMap m_dataMap; 

Now this approach does not work for a number of reasons (one of which is that the dataMap property is available as data in childModel, which is overridden by default property data in any type of QML type). Any possible solution to this problem?

+4
source share
2 answers

I am currently working on an application that requires the visualization of isolated branches of a massive (hundreds of millions of objects) tree. Since this is a tree, it is very similar to your problem, namely, nested models.

My solution was to make a form of abstraction. Since the tree already exists and is a completely different design layer than the GUI, I use a proxy object that contains a model class that attaches to the rendered node tree. The model is just an adapter for viewing the list for access to basic data.

The model provides the "object" and "type" roles, which the "root" delegates to create the user interface element for the child nodes, and the object role is used to create a proxy for attaching to each child element, so effectively, I get indirectly nested models.

Each delegate is basically a loader (but not a Q20 Loader element) that receives a pointer to each object and its type from model roles, so it creates a proxy for this type, and the user interface element type + ".qml" attached to proxy server as a data source.

I can’t share any code, but I hope you get the picture. This approach sounds a bit complicated, but it offers several huge advantages:

  • Qt heavy objects are created only for required objects
  • multiple user interface elements can use the same proxy server and model.
  • one delegate can create an arbitrary number of completely different user interface elements.
  • it works for a tree that has an arbitrary number of different types with different properties, and only two roles are used to achieve this. Each object gets its own unique user interface element, with access to all data of the base object through a proxy. Good luck achieving this with dynamic roles.
  • a proxy is also used to inform each user interface about changes in the data of each data element of the base object
+2
source

I found this very useful article that helped solve the problem https://lemirep.wordpress.com/2013/04/06/a-practical-case-exposing-qt-c-models-to-qml/ . The approach is to create another ListModel class (derived from QAbstracListModel) inside the model class. In my example, I replace QVariantMap dataMap() with another ListModel dataModel() . Please note that this requires other changes (which can be found on the link provided)

+1
source

All Articles