'Custom view with model and delegate both accessible from both QML files
Although I already figured it out, it took quite a while. If you know a less convoluted solution - please share.
I'd like to provide a custom View that works with any type of model (with arbitrarily named fields):
model: 3model: [ "red", "yellow", "green" ]model: [ {color: "red"}, {color: "yellow"}, {color: "green"} ]model: ListModel{ ListElement{color: "red"}; ListElement{color: "green"} }- subclassed
QAbstractItemModeland such...
To do that I decided to provide a property Component delegate that user would populate with a visual Item that would be inserted deep into my View.
However, the View also needed to access some information from that same delegate because otherwise it would either promote unneeded code duplication, or unneeded complexity of proxy model.
MyView {
mymodel: ["red", "blue"]
mydelegate: Text {
text: "color=" + modelData.name
must_also_somehow_set_color_of_MyView_element_to: modelData.color
}
}
...where MyView should be something like:
Column {
Repeater {
model: mymodel
delegate: Rectangle {
color: somehow_get_color_from_mydelegate
Text {} // <--- instantiate mydelegate here with data from mymodel
}
}
}
Doing so seems easy but a naive attempts didn't work. The solution posted as an answer did for me.
Solution 1:[1]
The trick is that model which is visible to Repeater or Instantiator's delegate contains everything that is visible to said delegate including index and modelData.
Said model can be used as a parameter to ListModel.append() to create a ListModel with a single element.
It can then be assigned as a model to a Repeater which will load the delegate with a copy of all context properties that QML normally derives from the element of View's model including index, modelData and model itself.
Upon instantiation, Repeater/Instantiator fires onItemAdded/onObjectAdded signal, which can be used as a cue to obtain a reference to the instance of View's delegate
User of the View can be asked to provide a root property in the delegate that would store obtained/calculated value which can be used by a View
Alternatively, the View can contain another Repeater or Instantiator and request another delegate to obtain values it itself needs.
Or a container type can encapsulate both View's data and visual Item.
Example:
MyView.qml
import QtQuick 2.0
import QtQml.Models 2.1
Column {
property var mymodel
property Component mydelegate
Repeater {
model: mymodel
delegate: Rectangle {
width: childrenRect.width; height: childrenRect.height
//color: model.color //works if "mymodel" has role "color"
property var myitem: null //this will hold instance of mydelegate
color: ( null !== myitem
&& undefined !== myitem.bgcolor )
? myitem.bgcolor : "transparent" //reads property of mydelegate
// <-- mydelegate will be injected here
Repeater {
delegate: mydelegate
model: ListModel{
Component.onCompleted: append(model)
}
onItemAdded: myitem = item
onItemRemoved: myitem = null
}
}
}
}
UsageExamples.qml
import QtQuick 2.0
import QtQuick.Window 2.0
Window{
visible: true
Row {
spacing: 10
MyView {
mymodel: ListModel {
ListElement{ name: "roses"; color: "red"; }
ListElement{ name: "violets"; color: "blue"; }
}
mydelegate: Text {
text: name
property color bgcolor: model.color
}
}
MyView {
mymodel: [{name: "roses", color: "red"}, {name: "violets", color: "blue"}]
mydelegate: Text {
text: modelData.name
property color bgcolor: modelData.color
}
}
MyView {
mymodel: ["red", "blue"]
mydelegate: Text {
text: "color="+modelData
property color bgcolor: modelData
}
}
}
}
Solution 2:[2]
I think you're really looking for a Loader to instantiate the delegate, rather than a second Repeater. You can also simplify a bit by using aliases. Try something like this:
Column {
property alias mymodel: repeater.model
property Component mydelegate
Repeater {
id: repeater
delegate: Rectangle {
width: childrenRect.width; height: childrenRect.height
color: ( null !== loader.item
&& undefined !== loader.item.bgcolor )
? loader.item.bgcolor : "transparent"
Loader {
id: loader
sourceComponent: myDelegate
}
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jack White |
| Solution 2 |
