Search code examples
c++qtqmlqabstractitemmodel

What are the downsides of a QAbstractListModel containing objects in QML?


Qt offers the possibility to combine C++ models with QML and suggests three approaches in the docs:

  • QStringList
  • QObjectList
  • QAbstractItemModel

The two former are extremely simple to use, e.g. QObjectList:

// in C++
QList<QObject*> dataList;
dataList.append(new DataObject("Item 1", "red"));

// in QML
ListView {
    model: dataList
    delegate: Text { text: name }
}

but they both come with a strong caveat:

Note: There is no way for the view to know that the contents of a QList has changed. If the QList changes, it is necessary to reset the model [...]

QAbstractItemModel is difficult to use with objects because the objects properties are not directly exposed and therefore keeping them in sync takes quite a bit of effort.

However, it is possible to wrap a QList in a QAbstractItemModel and obtain a super simple model. See here: Implementation 1, Implementation 2


Is there a reason why Qt does not implement this natively? Performance? Memory management issues? It seems such an obviously good idea and with ObjectModel they already implement something similar.


Solution

  • The one prominent downside of the usage of QObject as a model item is because the base class is pretty big, it is kind of a "god object" (which is an anti-pattern) that contains a whole lot of stuff you don't really need most of the time. As a result, it has about 160 bytes of "overhead" on top of any model data that you may have. Which may be problematic if you have a big model with lots of items, and the items themselves are relatively small. You end up with a lot of overhead.

    A QObjectList as a model is always a bad idea, unless you are doing something entirely trivial. Since it doesn't implement the proper interface to notify referencing views of changes, the only way is to force an update, which will redraw the entire model each time rather than just the changes.

    There is no requirement on what item objects are, as long as you implement the model properly.

    The second implementation in particularly useful for a number of reasons:

    • you don't need to bother with implementing a specific "static" model with fixed roles for each and every usage scenario
    • your model items can have fundamentally different properties, you are not limited to a model "schema"
    • you automatically get notifications for bindings in QML since you are dealing with QObject and Q_PROPERTY
    • you can define models in declarative, and you can even nest models to create tree structures, which you cannot do with ListModel.
    • you can define the actual model items in pure QML without having to recompile all the time, a.k.a rapid prototyping, and when done, you can simply port the objects to C++
    • at the same time, on top of all the advantages, the model is actually much simpler to implement and maintain than a regular "rigid" model, the role lookup is faster, since you essentially have a single object role and no lookup whatsoever, there is no need to implement data change signals for roles and so on... easy peasy