逆流布局顺序

时间:2017-07-19 14:17:20

标签: qml qt5 qtquick2

我希望Flow从左到右添加对象,但每行都在右边对齐。

import QtQuick 2.0
import QtQuick.Controls 2.0
Flow {
    width: 400
    anchors.right: parent.right
    spacing: 2
    Repeater {
        model: ['a', 'b', 'c', 'd', 'e', 'f', 'g']
        delegate: Button {
            text: modelData
            width: (83 * (model.index + 1)) % 100 + 30
        }
    }
}

我将Flow向右对齐,但其中的行始终从Flow的左边缘开始。我可以设置

layoutDirection: Qt.RightToLeft

将行与右对齐,但项目的顺序也会相反。

如果我反转模型(在此示例中可以通过调用reverse()来调用ListModel,我需要撤消ProxyModela将在左侧,但行没有问题。

我怎么能得到这样的东西?

2 个答案:

答案 0 :(得分:1)

   
import QtQuick 2.5
import QtQuick.Controls 2.1

ApplicationWindow {
    id: root;
    width: 640
    height: 480
    visible: true

    Rectangle {
        z: -1
        color: "#80000000"
        width: flow.width
        height: flow.height
        anchors.centerIn: flow
    }

    Flow {
        id: flow
        width: 400
        anchors.right: parent.right
        spacing: 2

        Repeater {
            id: repeater
            property real remainingRowSpace: flow.width
            property real indexOfFirstItemInLastRow: 0

            model: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q']
            delegate: Rectangle {
                property real buttonWidth: (83 * (model.index + 1)) % 100 + 30

                color: "#80000000"
                width: buttonWidth
                height: childrenRect.height

                Button {
                    x: parent.width - width
                    text: modelData
                    width: parent.buttonWidth
                }
            }

            onItemAdded: {
                var spacing = parent.spacing

                // Check if new row.
                if (item.width > remainingRowSpace) {
                    // Increase width of first item push row right.
                    itemAt(indexOfFirstItemInLastRow).width += remainingRowSpace
                    // Reset available space
                    remainingRowSpace = parent.width
                    // Store index of item
                    indexOfFirstItemInLastRow = index
                    // Don't need to subtract spacing for the first item
                    spacing = 0
                }

                remainingRowSpace -= (item.width + spacing)

                // Handle when no more rows will be created.
                if (index === repeater.count - 1) {
                    itemAt(indexOfFirstItemInLastRow).width += remainingRowSpace
                }
            }
        }
    }
}

它不是一个多功能或动态的解决方案,但它有效。

答案 1 :(得分:0)

  

这仍然是一项正在进行中的工作,但可能仍适用于某些人

正如 Tony Clifton 的解决方案一样,它使用Repeater及其onItemAdded - 方法,但使用Qt.binding来保存更多动态。 Tony Clifton 的解决方案并不优越,选择可能取决于用例。

上升空间:

  • 动态更改个人Item - 宽度
  • 动态显示 ReversedFlow
  • 的宽度

缺点:

  • 首先填充底行。第一行可能不满(对于某些用例,这可能更好)

当与ListModel一起使用并且新条目正在insert()时,两种解决方案都无法正常工作。当模型被完全替换时(例如JSArray和手动调用modelChanged()),两种解决方案都应该有效。

在某种意义上,这两个解决方案都不是Flow,因为Repeater负责布局,所以你可以抛出任意对象。因此Repeater必须创建Item s。我没有使用ObjectModel。摆脱中继器将是我最后的关注点。

Item {
    id: root
    visible: false
    width: 400
    height: (rep.count > 0 ? rep.itemAt(0).y * -1 : 0)
    anchors.centerIn: parent
    property real spacing: 5
    Item {
        anchors.bottom: parent.bottom
        anchors.right: parent.right
        anchors.left: parent.left
        Repeater {
            id: rep
            model: ListModel {
                id: bm
                ListElement { text: "a" }
                ListElement { text: "b" }
                ListElement { text: "c" }
                ListElement { text: "d" }
                ListElement { text: "e" }
                ListElement { text: "f" }
                ListElement { text: "g" }
                ListElement { text: "h" }
                ListElement { text: "i" }
            }

            onItemAdded: {
                console.log(index, item, itemAt(index - 1))
                item.anchors.right = Qt.binding(
                            function() {
                                if (rep.count === index + 1) return parent.right
                                var neighbor = rep.itemAt(index + 1)
                                if (neighbor.x - item.width - root.spacing < 0) return parent.right
                                return rep.itemAt(index + 1).left
                            }
                            )
                item.anchors.bottom = Qt.binding(
                            function() {
                                if (rep.count === index + 1) return parent.bottom

                                var neighbor = rep.itemAt(index + 1)
                                if (neighbor.x - item.width - root.spacing < 0)
                                    return neighbor.top
                                return neighbor.bottom
                            }
                            )
                item.anchors.rightMargin = Qt.binding(
                            function() {
                                return (item.anchors.right === parent.right ? 0 : root.spacing)
                            }
                            )
                item.anchors.bottomMargin = Qt.binding(
                            function() {
                                return (item.anchors.bottom === rep.itemAt(index + 1).top ? root.spacing : 0)
                            }
                            )

            }
            delegate: Button {
                text: modelData
                property int count: 0
                width: (83 * (index + count + 1)) % 100 + 30
                onClicked: {
                    count++
                }
            }
        }
    }

    Rectangle {
        id: debug
        anchors.fill: parent
        color: 'transparent'
        border.color: 'red'
    }
}

这背后的想法是在添加对象时初始化锚点的绑定,如果有足够的空间,我将每个Item锚定到右侧或它的后继者。<登记/> 我还将Item的底部锚定在它的旁边,如果它在他旁边,或者它的顶部,如果它开始一个新行。如果它没有继承者,它将被锚定到父母的底部 后一个事实,使这个奇怪的结构有两个必要的封闭Item。外部将真正包围一切,并动态增长,但这不是那个,我锚定整个链,当我锚定到底部。如果我根据height更改childrenRect.height,我会在具有奇怪效果的绑定循环中结束,因为Items的y值不会保持不变。最初它会起作用,但是当项目因尺寸变化而移动时,它会破裂。

相关问题