2017-07-19 41 views
0

我想要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将到左侧,但行是无序。

我怎么能达到那样的东西?

回答

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

这不是一个非常通用的或动态的解决方案,但它的工作原理。

+0

这是一个不错的解决方案,对于这种情况,创建后所有东西都保持静态。如果模型发生变化,则需要重新布置一切。项目大小的变化也需要重新计算一切。这仍然是一个不错的解决方案。 – derM

0

这仍然是一个进展中的工作,但可能仍然是可用于某些人

正如托尼·克利夫顿的解决方案,它采用了Repeater和它的onItemAdded - 方法,但使用Qt.binding保持东西更多动态。 这不是优于托尼克利夫顿的解决方案和选择可能取决于用例。

上升空间:

  • 动态向ReversedFlow

缺点的宽度的各个Item -width

  • 动态的变化:

    • 填充底部排第一。第一行可能不完全(对于某些usecases这可能会更好)

    两种解决方案都无法正常工作,具有ListModel使用,新的条目正在insert()版时。这两种解决方案都应该在模型完全更换后(例如JSArrays和modelChanged()的手动呼叫)。

    从某种意义上说,两种解决方案都不是Flow s,因为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,我将以具有奇怪效果的绑定循环结束,因为项目的y值不会保持不变。最初它会起作用,但是当物品因尺寸变化而移动时,它会破裂。