Reputation: 19800
I have an QT which gui is created in QML. I'm using a custom component which uses a model to display data. At runtime, this model will change. However the changes are not reflected.
MyCustomComponent
{
property var myModel: [
{
icon: "qrc:/resources/my_icon1.png",
data: "Initial text",
},
{
icon: "qrc:/resources/my_icon2.png",
data: "Initial text",
}
]
model: myModel
property int myProp: 0
onMyPropChanged:
{
refreshModel()
}
function refreshModel()
{
console.error("refreshModel: before: myModel:" + myModel[0].data + ", model:" + model[0].data);
myModel[0].data = "alternate text"
console.error("refreshModel: after: myModel:" + myModel[0].data + ", model:" + model[0].data);
}
}
Outcome:
refreshModel: before: myModel:Initial text, model:Initial text
refreshModel: after: myModel:alternate text, model:Initial text
So at runtime myProp
is changed, refreshModel
will be called. However the model
itself remains unchanged, the myModel
does change.
Changing model directly and not does not work either. (so remove the myModel in-between property).
What do I need to do differently?
Side note:
Initially I was using a ListModel
+ ListElement
, but this has other issues where I'm looking for an alternative (ListElement: cannot use script for property value)
Upvotes: 1
Views: 2704
Reputation: 241
As the other answers already point out, a JSON structure is a variant type. The modelChanged signal thus only fires in case you reassign a new value (new JSON) to the property. Doing small changes to parts of the structure will not fire the signal.
Also Note: When using such a variant model for e.g. your ListView, you will suffer from performance and usability drawbacks as well. Even if you modify the model and fire the signal manually, the view requires a full re-draw. It only knows that "Something in the model changed".
To avoid this, you can transform your JSON into an actual ListModel type (QAbstractListModel implementation), using JsonListModel:
MyCustomComponent
{
property var myJson: [
{
id: 1,
icon: "qrc:/resources/my_icon1.png",
data: "Initial text",
},
{
id: 2,
icon: "qrc:/resources/my_icon2.png",
data: "Initial text",
}
]
model: JsonListModel {
source: myJson
keyField: "id"
}
property int myProp: 0
onMyPropChanged:
{
refreshModel()
}
function refreshModel()
{
myJson[0].data = "alternate text"
myJsonChanged() // emit changed signal, JsonListModel thus also updates
}
}
You can find more details about the JsonListModel and its usage here.
Upvotes: 0
Reputation: 5336
Have a look at what the Qt documentation says about the var
type.
It is important to note that changes in regular properties of JavaScript objects assigned to a var property will not trigger updates of bindings that access them.
So in order for the update to be triggered, you have to manually emit the myModelChanged
signal, just after you modify the model.
function refreshModel()
{
console.error("refreshModel: before: myModel:" + myModel[0].data + ", model:" + model[0].data);
myModel[0].data = "alternate text"
myModelChanged()
console.error("refreshModel: after: myModel:" + myModel[0].data + ", model:" + model[0].data);
}
Upvotes: 4
Reputation: 1
Indeed, modifying the myModel structure will not trigger a signal. I got used to this pattern, which has the advantage of using an immutable structure:
MyCustomComponent
{
function computeModel(initial)
{
return [
{
icon: "qrc:/resources/my_icon1.png",
data: initial ? "Initial text" : "alternate text",
},
{
icon: "qrc:/resources/my_icon2.png",
data: "Initial text",
}
];
}
model: computeModel(true)
property int myProp: 0
onMyPropChanged:
{
model = computeModel(false);
}
}
Upvotes: 0