将采用模型并将其显示在页面中分隔的网格中的 Qt 组件

Posted

技术标签:

【中文标题】将采用模型并将其显示在页面中分隔的网格中的 Qt 组件【英文标题】:Qt component that would take model and display it in grid separated in pages 【发布时间】:2017-09-19 11:04:34 【问题描述】:

我想创建一个可重用的组件,我可以在其中传递模型,即

["red", "green", "blue", "black", "orange", "pink", "gray", "navy", "magenta"]

它会用模型数据的矩形填充Grid。如果模型中有超过 6 个项目,它将填充其他“页面”。

它应该是这样的:

目前我使用 StackLayout 有 2 个 Grid 项目和 Repeater 在其中,我将我的模型分为 2:

model: ["red", "green", "blue", "black", "orange", "pink"]
model: ["gray", "navy", "magenta"]

用矩形填充每个“页面”。

为每个页面动态地将模型分成不同部分的编写逻辑似乎过于复杂。 我试过GridView,但我找不到像Grid这样的重要属性:

topPadding: 10
bottomPadding: 10
leftPadding: 20
rightPadding: 20
spacing: 10
columns: 2

我的例子来源:

import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.0

Window 
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Rectangle 
        id: mainArea
        width: 400
        height: 400
        color: "beige"

        StackLayout 
            id: stackLayout
            anchors.fill: parent
            currentIndex: 0

            Grid 
                anchors.fill: parent
                topPadding: 10
                bottomPadding: 10
                leftPadding: 20
                rightPadding: 20
                spacing: 10
                columns: 2
                property int maxRows: 3

                Repeater 
                    model: ["red", "green", "blue", "black", "orange", "pink"]

                    Rectangle 
                        width: (parent.width - parent.leftPadding - parent.rightPadding - parent.spacing) / parent.columns
                        height: (parent.height - parent.topPadding - parent.bottomPadding - (parent.maxRows - 1) * parent.spacing) / parent.maxRows
                        color: modelData
                    
                
            

            Grid 
                anchors.fill: parent
                topPadding: 10
                bottomPadding: 10
                leftPadding: 20
                rightPadding: 20
                spacing: 10
                columns: 2
                property int maxRows: 3

                Repeater 
                    model: ["gray", "navy", "magenta"]

                    Rectangle 
                        width: (parent.width - parent.leftPadding - parent.rightPadding - parent.spacing) / parent.columns
                        height: (parent.height - parent.topPadding - parent.bottomPadding - (parent.maxRows - 1) * parent.spacing) / parent.maxRows
                        color: modelData
                    
                
            
        
    

    Button 
        anchors.bottom: mainArea.verticalCenter
        anchors.bottomMargin: 5
        anchors.left: mainArea.right
        text: "<"
        onClicked: stackLayout.currentIndex = 0
    
    Button 
        anchors.top: mainArea.verticalCenter
        anchors.topMargin: 5
        anchors.left: mainArea.right
        text: ">"
        onClicked: stackLayout.currentIndex = 1
    

【问题讨论】:

您想让模型成为数组还是ListModel @derM 数组。我猜ListModel会更复杂。 不过,您可以使用here 的解决方案......我在开始使用 QML 后不久就写了它,还有很多需要改进的地方。 DelegateModel 的使用可能会更快,如果您将其替换为 C++ ...ProxyModel,例如 QSortFilterProxyModel 或 not-so-identity-proxymodel,但后者需要 ListModel afaik。 【参考方案1】:

对于简单的数组,可以使用array.slice(from, to)方法为每个页面创建模型。

property int page: 0

Button 
    text: "up"
    onClicked: page++


Grid 
    y: 100
    rows: 2
    columns: 2
    Repeater 
        model: ["red", "green", "blue", "black", "orange", "pink", "gray", "navy", "magenta", "yellow", "cyan", "brown", "lightblue", "darkred"].slice(page * 4, (page + 1) * 4)
        Rectangle 
            width: 100
            height: 100
            color: modelData
        
    

对于QAbstractItemModel-descendents,如果你想要一个仅QML的解决方案,你可以使用here解释的方法。

否则,您可能会利用 QSortFilterProxyModelQIdentityProxyModel 在 C++ 中实现更快的过滤器模型

请参阅 GrecKothis 实现,了解如何让 SortFilterProxyModel 在 QML 中工作。

【讨论】:

slice ofc。我的错:-)【参考方案2】:

您可以尝试过滤模型以仅显示特定索引。

或者更简单,您可以根据每页的索引和项目简单地设置委托可见性:

ApplicationWindow 
  id: main
  visible: true
  width: 640
  height: 480
  color: "darkgray"

  property int maxRows: 3
  property int page: 0
  property int iperp: 2 * maxRows

  Grid 
    anchors.fill: parent
    topPadding: 10
    bottomPadding: 50
    leftPadding: 20
    rightPadding: 20
    spacing: 10
    columns: 2

    Repeater 
      id: rep
      model: ["red", "green", "blue", "black", "orange", "pink", "gray", "navy", "magenta", "yellow", "cyan", "brown", "lightblue", "darkred"]

      Rectangle 
        width: (parent.width - parent.leftPadding - parent.rightPadding - parent.spacing) / parent.columns
        height: (parent.height - parent.topPadding - parent.bottomPadding - (maxRows - 1) * parent.spacing) / maxRows
        color: modelData
        visible: 
          var i = page * iperp
          return index >= i && index < i + iperp
        
        Text 
          anchors.centerIn: parent
          text: index
        
      
    
  
  Row 
    anchors.horizontalCenter: main.contentItem.horizontalCenter
    anchors.bottom: main.contentItem.bottom
    Button 
      text: "<<"
      enabled: page
      onClicked: --page
    
    Button 
      text: ">>"
      enabled: page < rep.count / iperp - 1
      onClicked: ++page
    
  

【讨论】:

喜欢这个解决方案。我不喜欢我使用StackLayout,所以这正是我想要的。 对于小型模型,这是一个简单的解决方案。对于大型模型,您将有 Rectangles 的大量开销。 Repeater 总是创建所有实例。 Grid 只是忽略所有 Items,没有尺寸或布局可见性。 (From Documentation) "如果 Grid 中的某个项目不可见,或者它的宽度或高度为 0,则该项目将不会被布局并且在其中不可见列。” 您可以将Grid 更改为GridView 并将contentItem 分区以始终显示正确的部分。 是的,我快速检查了一下,确实是这样。所有项目均已创建。尽管如此,对于不是很大的模型仍然非常有用。在实际生产中,我使用自己的代理模型,可以通过 JS 函子进行过滤和排序。

以上是关于将采用模型并将其显示在页面中分隔的网格中的 Qt 组件的主要内容,如果未能解决你的问题,请参考以下文章

获取选择值列表作为隐藏字段中分隔的管道并提交

列中分隔的字符串的PHP数组到关联数组[重复]

Qt 如何从 QVector 中的数据创建位图并将其显示在小部件上?

将模型绑定到 Qt TableView

在 QT 中的槽或函数之间保留值

如何从数组列表中分离数据并将其显示到列表视图中?