关于qt:具有可变列数的QML Repeater和QML Grid Layout

QML Repeater and QML Grid Layout with variable number of columns

我有一个模型,该模型由具有某些属性的对象组成,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ListModel {
    id: fruitModel

    ListElement {
        name:"Apple"
        color:"green"
        cost: 2.45
    }
    ListElement {
        name:"Orange"
        color:"orange"
        cost: 3.25
    }
    ListElement {
        name:"Banana"
        color:"yellow"
        cost: 1.95
    }
}

现在我想使用GridLayout显示此模型。对于每个属性,我想在GridLayout中使用一个元素,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GridLayout {
    columns: 3

    Text { text:"Apple" }
    Rectangle { color:"green" }
    SpinBox { value: 2.45 }

    Text { text:"Orange" }
    Rectangle { color:"orange" }
    SpinBox { value: 3.25 }

    Text { text:"Banana" }
    Rectangle { color:"yellow" }
    SpinBox { value: 1.95 }
}

关键是我可以轻松更改GridLayoutcolumns属性并使布局更窄(例如,适合小屏幕)。我可以使用Repeater来填充GridLayout。但是,这种方法将以错误的顺序填充我的GridLayout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GridLayout {
    columns: 3

    Repeater {
        model: fruitModel
        Text { text: name }
    }

    Repeater {
        model: fruitModel
        Rectangle { color: color }
    }

    Repeater {
        model: fruitModel
        SpinBox { value: value }
    }
}

使用Layout.columnLayout.row附加属性很浪费,因为我想轻松更改GridLayout中的列数。

有什么方法可以用一行一行的数据填充GridLayout吗?

UPD1:

我想要获得的行为:

enter image description here

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GridLayout {
    columns: parent.width > 235 ? 3 : 1

    Text { text:"Apple" }
    Rectangle { color:"green"; width: 40; height: 40 }
    SpinBox { value: 2 }

    Text { text:"Orange" }
    Rectangle { color:"orange"; width: 40; height: 40 }
    SpinBox { value: 3 }

    Text { text:"Banana" }
    Rectangle { color:"yellow"; width: 40; height: 40 }
    SpinBox { value: 1 }
}

UPD2:
@ m7913d的修改后的变体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
GridLayout {
    id: layout
    property int maxColumns: 3
    columns: parent.width > 235 ? maxColumns : 1

    Repeater {
        model: fruitModel
        Text {
            text: name
            Layout.row: layout.columns == maxColumns ? index : (maxColumns * index)
            Layout.column: 0
        }
    }

    Repeater {
        model: fruitModel
        Rectangle {
            Layout.preferredWidth: 30
            Layout.preferredHeight: 30
            color: col
            Layout.row: layout.columns == maxColumns ? index : (maxColumns * index + 1)
            Layout.column: layout.columns == maxColumns ? 1 : 0
        }
    }

    Repeater {
        model: fruitModel
        SpinBox {
            value: val
            Layout.row: layout.columns == maxColumns ? index : (maxColumns * index + 2)
            Layout.column: layout.columns == maxColumns ? 2 : 0
        }
    }
}

这是可行的,但解决方案不容易修改,并且有时在调整布局大小时会出现消息QGridLayoutEngine::addItem: Cell (1, 0) already taken


这是另一个解决方案:

The Idea: add the children in the right order

为此,我们需要确保模型条目的所有Item

1
2
3
4
5
6
7
8
9
10
11
12
GridLayout {
    id: gl
    columns: parent.width > 235 ? 3 : 1
}
Instantiator {
    model: fruitModel
    delegate: QtObject {
        property Item text: Text { parent: gl; text: model.name }
        property Item rect: Rectangle { parent: gl; color: model.color; width: 50; height: 50; }
        property Item spin: SpinBox { parent: gl; value: model.cost; }
    }
}

Note: This will fail when entries in the model will be inserted or reordered, as in this solution the entries are always appended.
Other than that, it will automatically support column changes


我将使用由RowColumn(或任何其他安排)填充的Column作为委托。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Column {
    id: rootCol
    anchors.fill: parent
    Repeater {
        model: fruitModel
        delegate: rootCol.width > 300 ? rowDel : colDel
    }

    Component {
        id: rowDel
        Row {
            Text { width: 100; height: 50; text: model.name }
            Rectangle { width: 50; height: 50; color: model.color }
            SpinBox { width: 150; height: 50; value: model.cost }
        }
    }

    Component {
        id: colDel
        Column {
            Text { width: 100; height: 50; text: model.name }
            Rectangle { width: 50; height: 50; color: model.color }
            SpinBox { width: 150; height: 50; value: model.cost}
        }
    }
}

或者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Column {
    id: rootCol
    anchors.fill: parent
    Repeater {
        model: fruitModel
        delegate: Flow {
            anchors {
                left: parent.left
                right: parent.right
            }

            Text { width: 100; height: 50; text: model.name }
            Rectangle { width: 50; height: 50; color: model.color }
            SpinBox { width: 150; height: 50; value: model.value }
        }
    }
}


一种可能的方法是使用条件列/行索引来扩展此方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
GridLayout {
    id:gridLayout
    columns: parent.width > 235 ? 3 : 1

    Repeater {
        model: fruitModel
        implicitHeight: 50
        Text {
            text: name
            Layout.row: gridLayout.columns == 3 ? index : 3 * index
            Layout.column: 0
        }
    }

    Repeater {
        model: fruitModel
        Rectangle {
            color: model.color
            implicitWidth: 50
            implicitHeight: 50
            Layout.row: gridLayout.columns == 3 ? index : 3 * index + 1
            Layout.column: gridLayout.columns == 3 ? 1 : 0
        }
    }

    Repeater {
        model: fruitModel
        SpinBox {
            value: value
            Layout.row: gridLayout.columns == 3 ? index : 3 * index + 2
            Layout.column: gridLayout.columns == 3 ? 2 : 0
        }
    }
}