'Populate GridLayout with Repeater
I try to add cells to my GridLayout by using a Repeater. My data is stored in a model and containing two properties per element:
TitleValue
My goal is to get a GridLayout containing the Title in first cell and the Value in the second cell of each row.
GridLayout {
id: someId
columns: 2
rowSpacing: 5
columnSpacing: 5
anchors.margins: 5
anchors.left: parent.left
anchors.right: parent.right
Repeater {
model: myModel
Label {
text: modelData.title
}
TextArea {
text: modelData.value
}
}
}
But QML Repeater allows only one element. Any ideas how I could get the layout I want?
+------------+---------------------------------------+
| | |
| title0 | value0 |
| | |
| | |
+------------+---------------------------------------+
| | |
| | |
| title1 | value1 |
| | |
| | |
+------------+---------------------------------------+
| | |
| title2 | value2 |
| | |
| | |
+------------+---------------------------------------+
Solution 1:[1]
You can use GridLayout.flow to specify in which order the cells should be filled, i.e. row- (GridLayout.LeftToRight) or column-wise (GridLayout.TopToBottom). Note that you should specify the number of rows when using GridLayout.TopToBottom.
Using this solution, the (simplified) example of skypjack would become:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
Window {
width: 600; height: 400; visible: true
GridLayout {
anchors.fill: parent
// specify the flow and number of rows
flow: GridLayout.TopToBottom
rows: repeater.count
Repeater {
id: repeater
model: [ "title1", "title2", "title3", "title4", "title5", "title6" ] // example model
Label {
Layout.fillWidth: true
Layout.fillHeight: true
text: modelData
}
}
Repeater {
model: [ "value1", "value2", "value3", "value4", "value5", "value6" ] // example model
TextArea {
Layout.fillWidth: true
Layout.fillHeight: true
text: modelData
}
}
}
}
Solution 2:[2]
The model-view principle assumes that each model node displays by different delegate component object. So I advice you to listen to @BaCaRoZzo's comment and do that with Column instead of GridLayout. Sure, QML is very flexible and you can do something like that:
Component {
id: labelDelegate
Label { text: myList.get(_index / 2).title }
}
Component {
id: textAreaDelegate
TextArea { text: myList.get(_index / 2).value }
}
ListModel {
id: myList
ListElement {title: "title1"; value: "value1"}
ListElement {title: "title2"; value: "value2"}
ListElement {title: "title3"; value: "value3"}
}
GridLayout {
anchors.fill: parent
columns: 2
Repeater {
model: myList.count * 2
delegate: Loader {
property int _index: index
sourceComponent: {
if(index % 2)
return textAreaDelegate;
else
return labelDelegate;
}
}
}
}
but that's too weird to use it in real project.
Solution 3:[3]
Nest as many elements as you want inside an Item in the Repeater's delegate and re-parent them to the GridLayout when the Item completes.
GridLayout {
id: grid
anchors.centerIn: parent
columns: 2
rowSpacing: 5
columnSpacing: 5
anchors.margins: 5
Repeater {
model: [
{ title: "title1 that's long", value: "value1" },
{ title: "title2 medium", value: "value2" },
{ title: "title3", value: "value3" }
]
delegate: Item {
Component.onCompleted: {
while (children.length) { children[0].parent = grid; }
}
Label {
Layout.alignment: Qt.AlignRight
color: "gray"
text: modelData.title
}
TextArea {
Layout.fillWidth: true
font.bold: true
text: modelData.value
}
}
}
}
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 | |
| Solution 2 | folibis |
| Solution 3 |

