0

Is an QAbstractListModel implementation with say roles

name, image, enabled, color, editable

Better than an implementation with a single role (forgive me for not being able to come up with a better name)

thing

which causes a QObject* with aforementioned Q_PROPERTYs to be returned?

The difference on QML side would be an extra "indirection" when accessing the values in say, a delegate:

model.thing.name

vs

model.name

I lean towards the QObject approach, because it disentangles the data view from the list model, and has a potential for reuse. It also doesn't require you to also implement the setData function. As far as I can tell, there are no specific pro's for the "many roles" option, unless of course it's impossible to properly define a proper QObject subclass wrapping the data (because e.g. it could make little sense conceptuallyfor specific cases).

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • I guess that question is largely opinion-based since on other questions this has been discussed sometimes in the comments. Most of the times I just use the `QQmlObjectListModel` that you can find in some GIT-Repositories like the one of *TheBootroo* - it exposes all properties of `MyItem` as roles and has a special role that exposes the item itself. Properties and Roles automatically update them selves. – derM - not here for BOT dreams Jun 27 '18 at 15:10
  • * Here is the link to aforementioned model: https://github.com/Cavewhere/lib-qt-qml-tricks - as disclaimer: This is not self-advertisement, since I am not [*TheBootroo*](https://stackoverflow.com/users/1195141/thebootroo) – derM - not here for BOT dreams Jun 27 '18 at 15:18
  • @derM I disagree this is largely opinion-based. There are various objective reasons that one of these might be preferred over the other. I just don't know them. Your suggestion is a nice midway, but still the question remains if using the QObject's properties or the list model's properties have any up/downsides. – rubenvb Jun 27 '18 at 16:02
  • Well then, my most rational explanation, why roles are necessary. – derM - not here for BOT dreams Jun 27 '18 at 16:22
  • As you can see, with the two answers, and the discussion in the comments - it is opinion-based, or at least not answerable in a general way. – derM - not here for BOT dreams Jun 27 '18 at 20:55

3 Answers3

2

Having roles in a model is helpful when you want to use it with features that rely on roles.

For example you want to feed your model to a ComboBox, if it has roles you can just specify a textRole to the ComboBox and it will do its thing. If using a single object role, you will have to modify the delegate to display your correct object property. Roles are also needed if you want to make use of ListView's section feature.

Like @derm said, it's also useful with a QSortFilterProxyModel (shameless plug: if your model has roles, it's super easy to filter or sort it with my SortFilterProxyModel library).

You mention reusability and having to reimplement stuff. That's a good point but it's totally doable to have a generic model with roles based on QObject properties. In fact it has been done and it is available with a very permissible license here : Thomas Boutroue's QQmlObjectListModel. From c++ it has the same API as a QList but it exposes a QAbstractListModel that is usable by QML. The roles are based on the properties of your objects, and when a notify signal is emitted, it emits the corresponding dataChanged signal. insertRows and friends are also handled automatically.

With that said, I don't see much point in doing a model with a single object role. If you want a proper model with rowsInserted/rowRemoved signals (and you should, unless you just have a static model, in this case a QVariantList or a QObjectList is enough), you'd have to implement it yourself anyway when you can just use QQmlObjectListModel and be done with it.

GrecKo
  • 6,615
  • 19
  • 23
0

Yes, you should.

The most fundamental reason to use roles is: It is the Qt way to write models.

Ok, this reason is nothing that really matters --- unless there are things that expect you to do it the Qt way...

So, there are reasons why you should implement roles, but that does not mean, you have to use them in QML - and depending on what you plan to do with your model, it will be unnecessary.

In my opinion, the most important reason is, that you have to implement that dataChanged-signal. If you don't do that, your model is worth as much as QVariantList.

Changes of the the properties of your object would only be reflected in the delegates that are generated but objects that are relying on the dataChanged-signal won't receive updates - unless you trigger it for the object-role when ever a property of that object has changed.
This on the other hand will have large impact on the delegates, since than all bindings have to be reevaluated.

Take for example the QSortFilterProxyModel - if you don't have the dataChanged-signal, it won't update the filter or sorting, if a value has been changed, since it is listening to the dataChanged-signal for that.

Ad hoc, I don't know any other cases that would use that from the Qt libraries, but there might be others.

However, as long as you don't intend to use any of those - you don't need to fire the dataChanged-signal.

Whether you have to really implement roles for that, I don't know. I have not tried to implement the dataChanged-signal without roles.

Code of QSortFilterProxyModel, that uses the dataChanged-signal


You don't need to
When you either don't use anything that relies on properly implemented roles or you reimplement that functionality that would rely on the roles your self.

0

Using roles means you have to stick to a pre-defined model schema.

Roles are good if your objects are low level, so you can expose various object members as roles.

But in the case of a QObject * model, that is entirely unnecessary. You are already utilizing Qt's meta object system, which can facilitate the same functionality in conjunction with the QML engine..

As long as the properties are properly implemented and have notify signals, it will all work seamlessly in QML.

And it is a big time saver too, as the model is generic, and you can populate it with objects, defined in QML without having to recompile the C++ code or have a dedicated model for each and every model.

Keep in mind that QObjects are rather big, and to present a significant overhead if you have scores of model items. If your model is huge or you are dealing with an already existing data set that is not available as QObject*s out of the box, it will be more efficient to implement a "classical" model with roles and whatnot.

As long as you don't run into its limitations, I'd say a single role QObject* model is the simpler, easier, faster, more flexible and more elegant solution.

As for sorting and filtering issue mentioned, the stock solutions obviously won't cut it. As mentioned here, it is possible to implement sorting and filtering which takes in a JS functor in which you can run your custom logic, which I dare say is actually better than the stock role based functionality. And again, you can get new code in it without having to recompile, it is even possible to drive it via functors generated at runtime.

dtech
  • 47,916
  • 17
  • 112
  • 190
  • So, you say if I use a JS functor that I pass from QML, I don't have to use `filterAcceptsRow` which IMHO is only called, when the `dataChanged`-signal in the model is implemented? How do you do that? – derM - not here for BOT dreams Jun 27 '18 at 18:20
  • @derM I manually invalidate and then call `sort()` and it is resorted and refiltered. – dtech Jun 27 '18 at 18:31
  • That means, you need to refilter and sort the whole thing when ever a property in any Item in the model is changing? I don't see how that is any better. – derM - not here for BOT dreams Jun 27 '18 at 18:36
  • Well, not on every change, but on every change that needs to be reflected by sorting or filtering. As I mentioned in the linked question, even though the implementation looks rather inefficient at first, it is really not all that bad. It is still immensely slower than what the GUI takes to update. – dtech Jun 27 '18 at 19:12
  • Most of the time it takes to update the GUI comes from a full rebuild of the view when you invalidate the filter. Assume you have a model of `Goods` each with a price tag and an availability. You sort for the price and filter for the availability. Now one of those `Goods` is changing the prize or the availability. You need a full refresh of the view, fully filter the model again and fully sort the model again. That seems tremendously inefficient to me, when you compare it to: Remove only the unavailable Item and destroy, move the now more expensive one. – derM - not here for BOT dreams Jun 27 '18 at 20:12
  • Well, it does the job for me, and I do have huge data models. It is definitely worth the overhead as opposed to spending my life implementing models with various and varying schema. If you ask me, fetching data all the way from the internet just because I changed the view from ascending to descending is tremendously inefficient too, but that's how 99.99% sites do it. In the end you have to balance things out, is something theoretically inefficient, memory inefficient, CPU inefficient, bandwidth inefficient etc.. and factor in what matters the most, what you can sacrifice and to what gains. – dtech Jun 27 '18 at 20:46