'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:

  • 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                        |
|            |                                       |
|            |                                       |
+------------+---------------------------------------+


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
            }
        }
    }
}

Screenshot of running QML code

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