列数可变的 QML 中继器和 QML 网格布局

Posted

技术标签:

【中文标题】列数可变的 QML 中继器和 QML 网格布局【英文标题】:QML Repeater and QML Grid Layout with variable number of columns 【发布时间】:2017-12-04 17:10:43 【问题描述】:

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

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 中使用一个元素,例如:

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

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:

我想要得到的行为:

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 的修改变体:

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

【问题讨论】:

Populate GridLayout with Repeater的可能重复 不幸的是“使用Repeater填充GridLayout”中的解决方案使用Layout.columnLayout.row附加属性,因此无法动态更改GridLayout的columns属性。 您可以展示您想要获得的图表或图像 @KamilZaripov,你调查过Flow吗?这可能会为您提供所需的响应式布局。 是的,也许会有所帮助,但是如何使用模型中的项目填充Flow 【参考方案1】:

我会使用由Rows 或Columns(或任何其他安排)填充的Column 作为代表。

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
        
    

或许:

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 
        
    

【讨论】:

是的,它有效,但在这种情况下,它不是GridLayout,而是RowLayoutColumnLayout 内。它们是有区别的。在GridLayout 中,同一列中的所有项目都具有相同的宽度,但在RowLayoutColumnLayout 内部却没有。 通过一些工作,您可以自己实现该行为。 GridLayout 不会变魔术。 是的,我知道没有GridLayout 也可以做到这一点,而且目前我在ColumnLayout 内部使用RowLayout,并且我手动为Items 设置了相同的宽度同一列。但这不是很方便的方法,我只是想知道是否有更简单的方法。显然没有。【参考方案2】:

这是另一个解决方案:

理念:按正确的顺序添加孩子

为此,我们需要确保所有Items 都是模型条目。

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; 
    

注意:当模型中的条目将被插入或重新排序时,这将失败,因为在此解决方案中,条目始终是附加的。 除此之外,它会自动支持列更改

【讨论】:

【参考方案3】:

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

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
        
    

【讨论】:

我已经尝试过这种方法,经过一些修改它可以工作,但它看起来有点难看,有时它会写入输出QGridLayoutEngine::addItem: Cell (1, 0) already taken等等。 @KamilZaripov:请编辑此答案,或自己发布答案。问题部分没有答案。

以上是关于列数可变的 QML 中继器和 QML 网格布局的主要内容,如果未能解决你的问题,请参考以下文章

QT quick基础QML学习2

QML在被MouseArea拖动时无法更改项目的位置

QML 加载并显示具有颜色属性的 .ply 网格

创建后如何将项目添加到 QML 网格?

具有动态列数的 QML TableView

QML加载并显示带有颜色属性的.ply网格