Choose between model/view or other approach
-
Looking at the Simple Tree Model Example I see that the real data is stored in a QList<QVariant> m_itemData inside the TreeItem object.
I don't understand why this data and the parent/child relationship aren't stored directly inside the TreeModel class?The advantage of this separatation is related with class cohesion. In this example, the TreeItem resposability is child, data and parent management. While the model is responsible for how to insert, edit or remove the data.
However, the point of this modeling idea is that TreeItem has parent that is another TreeItem that can be list of datas and another parent...Third, looking how many thing I have to implement with this pattern I've noticed that I should use many generic call/data type, like the data/setData function, based on column concept, and the QVariant, while I have many specific data and function that should do particular thing when the data is set.
In model design, you should consider how the date will be retrieved and manipulated. This partitioning makes it easier to locate the problem.
-
Looking at the Simple Tree Model Example I see that the real data is stored in a QList<QVariant> m_itemData inside the TreeItem object.
I don't understand why this data and the parent/child relationship aren't stored directly inside the TreeModel class?The advantage of this separatation is related with class cohesion. In this example, the TreeItem resposability is child, data and parent management. While the model is responsible for how to insert, edit or remove the data.
However, the point of this modeling idea is that TreeItem has parent that is another TreeItem that can be list of datas and another parent...Third, looking how many thing I have to implement with this pattern I've noticed that I should use many generic call/data type, like the data/setData function, based on column concept, and the QVariant, while I have many specific data and function that should do particular thing when the data is set.
In model design, you should consider how the date will be retrieved and manipulated. This partitioning makes it easier to locate the problem.
@KillerSmath thanks
Can you please make me an example of why it's easier work in this way?
What's the disavvantage of having the data and the method that use/manipule that inside the same object?Meanwhile I'm doing some test with the QAbstractItemModel and I've found another "disadvantage" of this method: the data is required using a row or a row + column system, but let say I want to have the color of a track, if I understand well I have to define that for example the column 2 is the color, the column 1 is the name, etc, so to have the color of a track I need to create an index that point to the row + column 2?
Or I should ignore the column and use the Role to have the right information? In that case, how could I set that?
I'm finding this way of working with the model more confusing than having a model with some getter/setter for his properties, that emit signal when a setter is called.Thanks
Cheers Mix ;) -
@KillerSmath thanks
Can you please make me an example of why it's easier work in this way?
What's the disavvantage of having the data and the method that use/manipule that inside the same object?Meanwhile I'm doing some test with the QAbstractItemModel and I've found another "disadvantage" of this method: the data is required using a row or a row + column system, but let say I want to have the color of a track, if I understand well I have to define that for example the column 2 is the color, the column 1 is the name, etc, so to have the color of a track I need to create an index that point to the row + column 2?
Or I should ignore the column and use the Role to have the right information? In that case, how could I set that?
I'm finding this way of working with the model more confusing than having a model with some getter/setter for his properties, that emit signal when a setter is called.Thanks
Cheers Mix ;)I'm finding this way of working with the model more confusing than having a model with some getter/setter for his properties, that emit signal when a setter is called.
But you do have that?
QAbstractItemModel::data()
,QAbstractItemModel::setData()
, and theQAbstractItemModel::dataChanged()
signal, do each of these respectively. Meanwhile, you write your class(es) to inherit from that and expose stuff as dedicated getter/setters as you see fit. -
I'm finding this way of working with the model more confusing than having a model with some getter/setter for his properties, that emit signal when a setter is called.
But you do have that?
QAbstractItemModel::data()
,QAbstractItemModel::setData()
, and theQAbstractItemModel::dataChanged()
signal, do each of these respectively. Meanwhile, you write your class(es) to inherit from that and expose stuff as dedicated getter/setters as you see fit.@JonB thanks :)
So you're suggesting to implement the setters and calling the QAbstractItemModel::dataChanged() signal? Is that enough?
And for the QAbstractItemModel::data() and QAbstractItemModel::setData()? I have to implement that like a sort of noop? Or I have to implement that for compatibility, for example returning the track/clip name when data is called with DisplayRole?Thanks again
Cheers Mix -
@JonB thanks :)
So you're suggesting to implement the setters and calling the QAbstractItemModel::dataChanged() signal? Is that enough?
And for the QAbstractItemModel::data() and QAbstractItemModel::setData()? I have to implement that like a sort of noop? Or I have to implement that for compatibility, for example returning the track/clip name when data is called with DisplayRole?Thanks again
Cheers Mix@mix359
I don't really understand your question (this is often the case for me!). Given that you have whatever data structures you want for your tracks etc., your derived class will implementQAbstractItemModel::data()
to return whatever is appropriate out of your data model. And if you needsetData()
(only read-write models do) that will set whatever in your model, and raisedataChanged
. In this derived class you can also write whatever methods you feel like to "wrap" certaindata/setData()
methods with dedicated get/setters, for your convenience. -
@mix359
I don't really understand your question (this is often the case for me!). Given that you have whatever data structures you want for your tracks etc., your derived class will implementQAbstractItemModel::data()
to return whatever is appropriate out of your data model. And if you needsetData()
(only read-write models do) that will set whatever in your model, and raisedataChanged
. In this derived class you can also write whatever methods you feel like to "wrap" certaindata/setData()
methods with dedicated get/setters, for your convenience.@JonB Sorry, probably the question wasn't clear...
Looking at the QAbstractItemModel system I see that al the data is requested and passed pointing at with an index and using a role. I would have many types of data and is not represented by the role system, so I would benefit from having a normal getter/setter (for example name/setName) system on the model instead of the data/setData methods.
If I understand well, I simply need to emit the dataChanged signal when one of my setter is called, right?
Or this way of using the model upset the idea of how the models work here in Qt?Thanks
Cheers Mix -
@JonB Sorry, probably the question wasn't clear...
Looking at the QAbstractItemModel system I see that al the data is requested and passed pointing at with an index and using a role. I would have many types of data and is not represented by the role system, so I would benefit from having a normal getter/setter (for example name/setName) system on the model instead of the data/setData methods.
If I understand well, I simply need to emit the dataChanged signal when one of my setter is called, right?
Or this way of using the model upset the idea of how the models work here in Qt?Thanks
Cheers Mix@mix359
Hi If you don't follow the Model View convention using roles and ModelIndex, none
of the normal view would be able to use your model.
The virtual function for the QAbstractItemModel defines the interfaces to the view so
you must return data via QAbstractItemModel::data()
However, its up to you how the actual data is stored behind the scene as long as
you follow the interface.
If you look at this sample
https://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html
it stores the data in
QVector<QVariant> itemData;
However, that could have been anything as the Views dont care, they just ask for data/setData as always. -
@JonB Sorry, probably the question wasn't clear...
Looking at the QAbstractItemModel system I see that al the data is requested and passed pointing at with an index and using a role. I would have many types of data and is not represented by the role system, so I would benefit from having a normal getter/setter (for example name/setName) system on the model instead of the data/setData methods.
If I understand well, I simply need to emit the dataChanged signal when one of my setter is called, right?
Or this way of using the model upset the idea of how the models work here in Qt?Thanks
Cheers Mix@mix359
Briefly: You are attempting to by-pass/replace thedata/setData()
methodology. No, you cannot emitdataChanged
in such a case.What @mrjj is saying is 100% correct. If you wish to use model/view you must respect the
data()
way of working. If not, then either there is no point using model/view or things will actually go wrong. You may supply dedicated get/setters in your derived class which present the data in that way, but underneath still calldata/setData()
to do the work; you must not have them be "standalone" and not usedata()
at all. -
Thanks for the answers, I'm taking the piece of the puzzle together :)
So back to the original question: I'll probably doesn't need to use my model with other widget, I will create custom widgets that use my data.
Does it worth to use the model/view system if I have to adapt it (creating many custom roles, etc) to my necessities?Cheers Mix
-
@mix359,
I am curious. What data do you think would not be able to be represented efficiently by the roles approach of data?@fcarney It's not a matter of efficiency, because many of the data are simple data that can be represented with a derivation of QVariant, so I can probably put all of this data in a QList o QMap.
It's a matter of control of data and operation that I can do to it, for example parse an input that is given to me from the widget and save it in some other way i need (thing that can be normally done in a getter or setter function).
With the model/view interface I will have to do the operation for all of the properties in the same data/setData function.The problem with the roles system is that I have many particular data like for an audio track if it's enabled (bool), if it's soloed (bool), his volume (float), a send volume (float), his height (int), his output channel, and so on... So I would have to create many custom roles to represent they.
Also in some case that custom roles couldn't be enough: let's say I have to save the volume to a send channel, and the number of send channel can change globally. How could I use a role in that case that should also take some data with him (in this case the send channel number)?Generally speaking I find more cleaner call the name of a properties on an object instead of save the value with a numeric index on a QList and access it defining many custom roles, but maybe I'm missing something so that's why I'm asking here ;)
Finally, talking of efficiency, correct me if I'm wrong, but using something like a QList or QMap for all the properties consume more memory then a simple object?
Thanks again ;)
Cheers Mix -
@mix359 said in Choose between model/view or other approach:
It's not a matter of efficiency, because many of the data are simple data that can be represented with a derivation of QVariant, so I can probably put all of this data in a QList o QMap.
You can use any storage/class/structure you want. It could be a database backend or anything. Also, you are not limited to using only the data() function. You could use that for a standard roles for listing things, but also define more getters/setters for the model object or another object if wanted. Use the index returned from the standard interface in getter/setter calls on that object to do more complex stuff. Just make sure you couch changes in the model that could affect what is shown in the views inside the correct begin/end data changed calls.
We use qml for a lot or our work and it is common for there to be stuff we do outside the model if it makes sense. Like you might want to return a custom object to the qml interface we may have more methods defined on the model itself. I don't know if your using qml, but it is nice for doing complex interactions. I am sure you could do the same if your using widgets.
The model/view code in Qt is really good at displaying lists and trees. No reason to reinvent that. Then add complex functionality if needed, where needed.