I've some instances of the following that I'm displaying in a repeater through a loaded component. And I'm trying to control the visibility of the repeated component:
property var modes : [new modeClass("Mode 1", "mode1", noteC1)];
function modeClass(name, representation, note) {
var active = true;
this.name = name;
this.representation = representation;
this.note = note;
this.activated = true;
Object.defineProperty(this, "activated", {
get : function () {
return active;
},
set : function (newActive) {
active = newActive;
if (!active)
note.selected = false;
this.dummy = active;
console.log(name, this.dummy);
},
enumerable : true
});
this.dummy = active;
}
And the repeater:
// Repeater pour les notes des modes
Repeater {
id : repModes
model : modes
//delegate : holeComponent - via Loader, to specify the "note" to display
Loader {
id : loaderModes
Binding {
target : loaderModes.item
property : "note"
value : modes[model.index].note
}
Binding {
target : loaderModes.item
property : "visible"
value : modes[model.index].activated
}
sourceComponent : holeComponent
}
}
I'm controlling the activated
property of the modeClass instance through some checkbox.
I don't manage to have the property-binding for the visibility to work. It works only a the instantiation of the component and does not react on the property changes.
I've tried several ways to do the binding:
With the property with the getter and setter
Binding {
target : loaderModes.item
property : "visible"
value : modes[model.index].activated
}
With "direct" property (no getter, no setter)
Binding {
target : loaderModes.item
property : "visible"
value : modes[model.index].dummy
}
With a "bottom-up" approach
Loader {
id : loaderModes
...
property bool showhide: modes[model.index].activated
//property bool showhide: modes[model.index].dummy
sourceComponent : holeComponent
}
and in the component:
Component {
id : holeComponent
Image {
id : img
property var note
visible : showhide
Work at the model level:
Repeater {
id : repModes
model : modes.filter(function(m) { return m.activated; })
//model : modes.filter(function(m) { return m.dummy; })
None of these works. The visibility of the holeComponents remains all the time the one at instantiation.
Any other approach ?
====================== Edit 27/10: a KISS version:
ColumnLayout {
id : layConfig
Repeater {
model : modes
delegate : CheckBox {
id : chkConfig
property var __mode : modes[model.index]
Layout.alignment : Qt.AlignLeft | Qt.QtAlignBottom
text : __mode.name + (__mode.activated ? "++" : "--")
checked : __mode.activated;
onClicked : {
console.log("onClik",__mode.name,modelData.name);
__mode.activated = !__mode.activated;
console.log("mode.activated ==> ",__mode.activated);
console.log("modelData.activated ==> ",modelData.activated);
}
}
}
}
I expect that when click the checkbox, the checkbox text is changed automaticaly by property-binding. IT DOES NOT. I guess it might be related to the property var __mode : modes[model.index]
. I should use instead modelData
. But with modelData
I don't have access to updated underlying object properties. And so it doesn't work neither.
Log output:
Debug: onClik Mode 1 Mode 1
Debug: mode.activated ==> **true**
Debug: modelData.activated ==> **false**
Debug: onClik Mode 1 Mode 1
Debug: mode.activated ==> false
Debug: modelData.activated ==> false
I found this hack on internet and have applied it to my case with success :
QML trick: force re-evaluation of a property binding
The issue lays in the fact, that qml does only re-evaluate the modelData
upon re-evaluation of the model
what it does only when there is an obvious change in the model. So a change in an underlying object of the model is not detected. And this is what I was trying to achieve.
So the hack is basically:
And the repeater:
// Repeater pour les notes des modes
Repeater {
id : repModes
model : ready?getActivatedModes():[] // awful hack
//delegate : holeComponent - via Loader, to specify the "note" to display
Loader {
id : loaderModes
Binding {
target : loaderModes.item
property : "note"
value : modes[model.index].note
sourceComponent : holeComponent
}
}
And the repeater for the controlling checkboxes :
Repeater {
model : __config
delegate : CheckBox {
id : chkConfig
property var __mode : __config[model.index]
Layout.alignment : Qt.AlignLeft | Qt.QtAlignBottom
text : __mode.name
checked : __mode.activated // init only
onClicked : {
__mode.activated = !__mode.activated;
ready= false; // awful trick to force the refresh
ready= true;
}
}
}
The ready=false; ready=true;
is, for qml, an obvious change in the model, so qml re-evaluates the model and repaints everything correctly.