accessing elements of structs in a list
-
Hi all -
I've defined a struct:
struct SceneFeature : public QObject { Q_OBJECT QML_ELEMENT public: QUuid m_featureId = QUuid(); Q_PROPERTY(QUuid uuid READ uuid WRITE setUuid NOTIFY uuidChanged FINAL) QUuid uuid() { return m_featureId; } ... }; Q_DECLARE_METATYPE(SceneFeature)
and I use it in this class:
typedef std::shared_ptr<SceneFeature> SceneFeaturePtr; Q_DECLARE_METATYPE(SceneFeaturePtr) typedef QList<SceneFeaturePtr> SceneFeatureList; Q_DECLARE_METATYPE(SceneFeatureList) class Scene : public QObject { Q_OBJECT QML_ELEMENT QUuid m_uuid { QUuid() }; public: Q_PROPERTY(QList<SceneFeaturePtr> featureList READ featureList WRITE setFeatureList NOTIFY featureListChanged FINAL) SceneFeatureList featureList() { return m_featureList; } ... }
and I try to access it from QML:
property Scene sceneCopy ListView { id: listView model: sceneCopy.featureList delegate: Text { text: model.uuid } // I realize this is wrong. ...
but model.uuid is undefined at run time. Can someone tell me what I'm doing wrong here?
EDIT: I should have pointed out that the model in my ListView appears to be good, judging from printouts. So, the problem appears to be in how I access it.
Thanks...
-
@J-Hilk said in accessing elements of structs in a list:
I',m not sure what featureList actually is. I have a feeling it's not a class derived from QAbstractListModel but rather a simple QList<QObjectDerivedClassInstances> ?
typedef QList<SceneFeaturePtr> SceneFeatureList; SceneFeatureList m_featureList; Q_PROPERTY(QList<SceneFeaturePtr> featureList READ featureList WRITE setFeatureList NOTIFY featureListChanged FINAL) QList<SceneFeaturePtr> featureList() { return m_featureList; }
So no, it's not derived from a Model class.
Your suggestion, along with my adding this code to my struct:
Q_PROPERTY(QUuid featureId READ featureId WRITE setFeatureId NOTIFY featureIdChanged FINAL) QUuid featureId() { return m_featureId; }
allows the QML to access the struct list. So, I think the answer is is that I don't necessarily need a proper model for access to the struct, as long as I've created Q_PROPERTY to its elements?
@mzimmers correct,
you can give your QML ListView literally anything as a model :D if it is an actuall Qt based ItemModel of some kind, you can access data via the roles of the model:
ListView { model: myModel delegate: Item { Text { text: model.someCustomRole // Access data via custom role } } }
for all other cases it is via modelData
ListView { model: ["a", "b", "c"] delegate: Item { Text { text: modelData // Access data for this specific index } } }
or manual index lookup
property var myModel: ["a", "b", "c"] ListView { model: myModel delegate: Item { Text { text: myModel[index] } } }
So, I think the answer is is that I don't necessarily need a proper model for access to the struct, as long as I've created Q_PROPERTY to its elements?
yes, it doesn't have to be a full blown QObject base class either, Q_GADET is enough, prevents you from using signals though.
-
yeah I'm looking again at the doc and and it confirms my thought : I don't remember ever seeing any delegate's component making a binding to the model itself. But directly to the model's properties. Look at ListView's (and other similar components) documentation : you never see the delegate refer to model.property, but directly to property instead.
my guess would be
delegate: Text { text: uuid }
and anyways, your list has no uuid property, only the elements of the list have one. It's a bit like making list.elementProperty instead of list[index].property.
-
@VRonin said in accessing elements of structs in a list:
Isn’t this the exact same as the “ QObjectList-based Model” example in the docs?
From the C++ side, it is, and I think I've done what I need to there. I suspect I'm messing things up on the QML side.
Unless...I actually need a model for my struct. I'm really hoping that's not the case here.
-
@VRonin said in accessing elements of structs in a list:
Isn’t this the exact same as the “ QObjectList-based Model” example in the docs?
This example looks irrelevant to me. If the property belongs to an item in the list, it's a non-sense accessing that property as if it was belonging to the list itself.
@mzimmers said in accessing elements of structs in a list:
Unless...I actually need a model for my struct. I'm really hoping that's not the case here.
A view without a suitable model doesn't make any more sense in my opinion.
-
@VRonin said in accessing elements of structs in a list:
Isn’t this the exact same as the “ QObjectList-based Model” example in the docs?
This example looks irrelevant to me. If the property belongs to an item in the list, it's a non-sense accessing that property as if it was belonging to the list itself.
@mzimmers said in accessing elements of structs in a list:
Unless...I actually need a model for my struct. I'm really hoping that's not the case here.
A view without a suitable model doesn't make any more sense in my opinion.
@ankou29666 said in accessing elements of structs in a list:
This example looks irrelevant to me. If the property belongs to an item in the list, it's a non-sense accessing that property as if it was belonging to the list itself.
So, what would you recommend in this instance?
-
as I said earlier :
delegate: Text { text: uuid }
seems to me the right way.
Since the delegate displays property for the current item, it's a non-sense to access that property as if it was a property of the list. As I understand by reading ListView / TableView / Repeater doc, the current item is implicit.But as your data is a simple list and not ListModel, I'm not certain that the previous correction will be sufficient.
-
QUuid is not a trivial type and therefore needs to be known to the QMetaObject system, apparently it is not registered by default.
do that via Q_DECLARE_METATYPE and qRegisterMetaType
Alternatively, as you can't do much with QUuid in QML itself, change the property to a QString and call toString() on your Quuid in the return/getter function
-
as I said earlier :
delegate: Text { text: uuid }
seems to me the right way.
Since the delegate displays property for the current item, it's a non-sense to access that property as if it was a property of the list. As I understand by reading ListView / TableView / Repeater doc, the current item is implicit.But as your data is a simple list and not ListModel, I'm not certain that the previous correction will be sufficient.
@ankou29666 said in accessing elements of structs in a list:
Since the delegate displays property for the current item, it's a non-sense to access that property as if it was a property of the list.
Are you talking about
text: model.uuid
? That's not accessing the property as it was a property of the list.model
in the delegate is different thanmodel
in the ListView. It's a context property fed by the view to the delegate, containing properties for each role of the delegate's row.Note that required properties are now preferred over context properties.
@mzimmers QML doesn't know how to access std::shared_ptr. Are you sure you want to share the ownership of your objects with QML?
-
@ankou29666 said in accessing elements of structs in a list:
Since the delegate displays property for the current item, it's a non-sense to access that property as if it was a property of the list.
Are you talking about
text: model.uuid
? That's not accessing the property as it was a property of the list.model
in the delegate is different thanmodel
in the ListView. It's a context property fed by the view to the delegate, containing properties for each role of the delegate's row.Note that required properties are now preferred over context properties.
@mzimmers QML doesn't know how to access std::shared_ptr. Are you sure you want to share the ownership of your objects with QML?
@GrecKo said in accessing elements of structs in a list:
@ankou29666 said in accessing elements of structs in a list:
Since the delegate displays property for the current item, it's a non-sense to access that property as if it was a property of the list.
Are you talking about
text: model.uuid
? That's not accessing the property as it was a property of the list.model
in the delegate is different thanmodel
in the ListView. It's a context property fed by the view to the delegate, containing properties for each role of the delegate's row.yep this is exactly what I was talking about. And reading once again documentation for Repeater, TableView, ListView, beyond the link posted by VRonin, I find no code, where the delegate explicitly calls model.property, it's always directly the property.
But thanks for the clue, I'll try that and check by myself as soon as I move a little further in my own project.
-
https://doc.qt.io/qt-6/qtquick-modelviewsdata-modelview.html#models
If there is a naming clash between the model's properties and the delegate's properties, the roles can be accessed with the qualified model name instead. For example, if a Text type had (non-required) type or age properties, the text in the above example would display those property values instead of the type and age values from the model item. In this case, the properties could have been referenced as model.type and model.age instead to ensure the delegate displays the property values from the model item. For this to work, you need to require a model property in your delegate (unless you are using context properties).
-
Thanks, very interesting.
-
QUuid is not a trivial type and therefore needs to be known to the QMetaObject system, apparently it is not registered by default.
do that via Q_DECLARE_METATYPE and qRegisterMetaType
Alternatively, as you can't do much with QUuid in QML itself, change the property to a QString and call toString() on your Quuid in the return/getter function
@J-Hilk said in accessing elements of structs in a list:
QUuid is not a trivial type and therefore needs to be known to the QMetaObject system, apparently it is not registered by default.
Yeah, I didn't choose a good example for my post. I'm getting the same results with a QString. It's somthing that I'm doing wrong.
-
@ankou29666 said in accessing elements of structs in a list:
Since the delegate displays property for the current item, it's a non-sense to access that property as if it was a property of the list.
Are you talking about
text: model.uuid
? That's not accessing the property as it was a property of the list.model
in the delegate is different thanmodel
in the ListView. It's a context property fed by the view to the delegate, containing properties for each role of the delegate's row.Note that required properties are now preferred over context properties.
@mzimmers QML doesn't know how to access std::shared_ptr. Are you sure you want to share the ownership of your objects with QML?
@GrecKo said in accessing elements of structs in a list:
Note that required properties are now preferred over context properties.
I assume you're referring to my code for sceneCopy - what would be the benefit of making that required?
@mzimmers QML doesn't know how to access std::shared_ptr. Are you sure you want to share the ownership of your objects with QML?
No, I'm not sure. I just like to use smart pointers wherever possible to reduce memory leaks. I can easily change this to see if it helps, but I still believe my problem lies elsewhere. This is kind of new to me - I've never done a "model within a model" before.
-
@J-Hilk said in accessing elements of structs in a list:
QUuid is not a trivial type and therefore needs to be known to the QMetaObject system, apparently it is not registered by default.
Yeah, I didn't choose a good example for my post. I'm getting the same results with a QString. It's somthing that I'm doing wrong.
@mzimmers I',m not sure what featureList actually is. I have a feeling it's not a class derived from QAbstractListModel but rather a simple QList<QObjectDerivedClassInstances> ?
than this:
ListView { id: listView model: sceneCopy.featureList delegate: Text { text: model.uuid } // I realize this is wrong.
should be
ListView { id: listView model: sceneCopy.featureList delegate: Text { text: modelData.uuid }
-
@mzimmers I',m not sure what featureList actually is. I have a feeling it's not a class derived from QAbstractListModel but rather a simple QList<QObjectDerivedClassInstances> ?
than this:
ListView { id: listView model: sceneCopy.featureList delegate: Text { text: model.uuid } // I realize this is wrong.
should be
ListView { id: listView model: sceneCopy.featureList delegate: Text { text: modelData.uuid }
@J-Hilk said in accessing elements of structs in a list:
I',m not sure what featureList actually is. I have a feeling it's not a class derived from QAbstractListModel but rather a simple QList<QObjectDerivedClassInstances> ?
typedef QList<SceneFeaturePtr> SceneFeatureList; SceneFeatureList m_featureList; Q_PROPERTY(QList<SceneFeaturePtr> featureList READ featureList WRITE setFeatureList NOTIFY featureListChanged FINAL) QList<SceneFeaturePtr> featureList() { return m_featureList; }
So no, it's not derived from a Model class.
Your suggestion, along with my adding this code to my struct:
Q_PROPERTY(QUuid featureId READ featureId WRITE setFeatureId NOTIFY featureIdChanged FINAL) QUuid featureId() { return m_featureId; }
allows the QML to access the struct list. So, I think the answer is is that I don't necessarily need a proper model for access to the struct, as long as I've created Q_PROPERTY to its elements?
-
@J-Hilk said in accessing elements of structs in a list:
I',m not sure what featureList actually is. I have a feeling it's not a class derived from QAbstractListModel but rather a simple QList<QObjectDerivedClassInstances> ?
typedef QList<SceneFeaturePtr> SceneFeatureList; SceneFeatureList m_featureList; Q_PROPERTY(QList<SceneFeaturePtr> featureList READ featureList WRITE setFeatureList NOTIFY featureListChanged FINAL) QList<SceneFeaturePtr> featureList() { return m_featureList; }
So no, it's not derived from a Model class.
Your suggestion, along with my adding this code to my struct:
Q_PROPERTY(QUuid featureId READ featureId WRITE setFeatureId NOTIFY featureIdChanged FINAL) QUuid featureId() { return m_featureId; }
allows the QML to access the struct list. So, I think the answer is is that I don't necessarily need a proper model for access to the struct, as long as I've created Q_PROPERTY to its elements?
@mzimmers correct,
you can give your QML ListView literally anything as a model :D if it is an actuall Qt based ItemModel of some kind, you can access data via the roles of the model:
ListView { model: myModel delegate: Item { Text { text: model.someCustomRole // Access data via custom role } } }
for all other cases it is via modelData
ListView { model: ["a", "b", "c"] delegate: Item { Text { text: modelData // Access data for this specific index } } }
or manual index lookup
property var myModel: ["a", "b", "c"] ListView { model: myModel delegate: Item { Text { text: myModel[index] } } }
So, I think the answer is is that I don't necessarily need a proper model for access to the struct, as long as I've created Q_PROPERTY to its elements?
yes, it doesn't have to be a full blown QObject base class either, Q_GADET is enough, prevents you from using signals though.
-
M mzimmers has marked this topic as solved on