Problems with qml models to instantiate components
-
So i am trying to instantiate a load of items by taking parameters from a list model.
The problem is, i don't want to always have to specify every possible parameter for every field in the model, unless it will be used. For example, sometimes i would want to use the default value of the qml component that is being instantiated.
For example, i have a model:@
ListModel {
id: keydisp1_r1
ListElement { keyCode: "1"; enabled: true; displayString: "1"; specialKey: "false" }
…
}
@Which i am trying to load into a repeater to instantiate a created KeyboardButton component.
@
Repeater {
id: row1
model: keydisp1_r1
KeyboardButton { keyCode: model.keyCode; enabled: model.enabled; displayString: "1"; specialKey: "false" }
}
@However i would like to be able to just define the element i want in the list model and then only pass over the ones that are defined, letting the KeyboardButton itself choose what to do if certain things are not passed to it.
For example:
@
ListModel {
id: keydisp1_r1
ListElement { keyCode: "1"; }
ListElement { keyCode: " "; enabled: false; displayString: "␣"; }
…
}
@I would also like to be able to choose to have ListElement parameters automatically defined if i don't specificy them - such as specifying an "enabled" property to true if i don't put one in.
The reason this is important is that this will be bound to by all buttons using that model, in order to know if they are currently enabled or not - it is not something that can just go to a default value inside the KeyboardButton later if not specified in the ListElement - as it needs to be manipulated on the ListElement later, at runtime.Alternatively, does anyone know of another way of doing it / a better model to use?
I was originally using VisualItemModels to instantiate buttons directly in there, but this causes a problem where if you load the same model in 2 places at the same time (for example, the same keyboard row), then only the first use of the model will actually receive the KeyboardButtons - the second use gets nothing.
I don't know whether this is a bug or it is intended, however it did kind of rule that method out.
Also, another possible reason not to do it that way is i imagine i could not override things like the width of the buttons etc in the place where the model is loaded - as there is no visual representation in view - as it is a visual model?So if anyone has any ideas or would like more information / a better explanation, that would be good.
Thanks for your time and help.
-
If i have understood a part of your problem, in response to "I would also like to be able to choose to have ListElement parameters automatically defined if i don’t specificy them"
You can "derive" your element from ListElement for example, in a DefaultElt.qml file:
@ListElement{
keyCode: model.keyCode; enabled: model.enabled; displayString: "1"; specialKey: "false"
}@
then if in your model you use
@ ListModel {
id: keydisp1_r1
DefaultElt { keyCode: "1"; }
DefaultElt { keyCode: " "; enabled: false; displayString: "-"; }
}@
I suppose that this will work. -
Ah thanks i didn't think of that.
What about if you only want to set (over-ride) a parameter from a ListElement if it is defined (either specifically or as a default like above) but otherwise let the element you are instantiating (e.g. KeyboadButton) define the property with its own logic?
e.g.:
@//inside a keyboardButton BorderImage {
property string keyCode
property string displayString: keyCode
width: label.width + 10 > sourceSize.width ? text.width + 10 : sourceSize.width
}@@ListModel {
DefaultElt { keyCode: "1"; }
DefaultElt{ keyCode: " "; displayString: "␣"; width: 300 }
}@Of course if you then instantiate with:
@KeyboardButton { keyCode: model.keyCode; displayString: model.displayString; width: model.width }@Then you will get undefined values passed to displayString and width where they are not used - rather than using the keyboardButtons in-built logic.
The stuff you posted before is helpful for part of my problems though :) -as i always want enabled to be set in the model, as i use the model to actually disable them, and want all instances disabled at once.
Thanks for your help!
-
mmmh i'm not sure i understand exactly when you get undefined values, it could be when the properties are not in the defaultElt, but as a default Element you could give always values even if not used.
If you don't know all properties of Default element before, perhaps you need many defaults elements....
-
Hmmm no i mean, the undefined values are deliberately undefined (in the default list element too) - i would like it that so if an undefined value is used then it doesn't try to override the KeyboardButton's default internal behaviour / settings.
-
Okay i solved the problem, see this for an explanation i wrote regarding it (applies to qt quick 1 / qt 4.8 at the time).
[quote]There appears to be a problem in Qt when trying to bind to model data that you are unsure the existence of. When binding normally, such as name: model.data , if model.data is undefined then the ‘name’ property will be overwritten with ‘undefined’, as opposed to not being bound to, where it would be free to supply its own default value / logic.
A way around this is to use a Binding element, for example:
@Binding {
target: tempButton
property: "displayString"
value: model.displayString
when: true
}@For some reason, even if you specify to always bind (like in the example above – when: true), an undefined value will not be bound. This is almost what you might expect as default binding behavior but is inconsistent with the previous method, where the property would get bound to undefined data.
Even with the ‘when’ omitted, it is still more awkward (and potentially slower?) to bind in this way, as you have to specify an id for the object that will be the target of the binding.
You cannot just specify the Binding element’s parent as a target, as this doesn’t appear to work for some reason – you have to specifically give the target an id.[/quote]