Reputation: 1930
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:
Title
Value
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 |
| | |
| | |
+------------+---------------------------------------+
Upvotes: 9
Views: 12910
Reputation: 11064
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
}
}
}
}
Upvotes: 7
Reputation: 2098
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
}
}
}
}
Upvotes: 1
Reputation: 50540
You can simply use two Repeater
s within a GridLayout
, as follows:
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 {
id: grid
anchors.fill: parent
columns: 2
rowSpacing: 5
columnSpacing: 5
anchors.margins: 5
// example models
property var titles: [ "title1", "title2", "title3", "title4", "title5" ]
property var values: [ "value1", "value2", "value3", "value4", "value5" ]
Repeater {
model: grid.titles
Label {
Layout.row: index
Layout.column: 0
Layout.fillWidth: true
Layout.fillHeight: true
text: modelData
}
}
Repeater {
model: grid.values
TextArea {
Layout.row: index
Layout.column: 1
Layout.fillWidth: true
Layout.fillHeight: true
text: modelData
}
}
}
}
The index
parameter is freely available and store the current row of the model.
By using the Layout.fillWidth
attached property you can control the width
of the single column.
Of course, each cell that belongs to a column has the same size of all the other cells of that column, unlike what happens using two Column
components.
This solution has a few drawbacks, but it's good if your purpose is mainly to print plain data from a model.
Upvotes: 18
Reputation: 12854
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.
Upvotes: 4