Eligijus Pupeikis
Eligijus Pupeikis

Reputation: 1125

Qt component that would take model and display it in grid separated in pages

I want to create a reusable component where I could pass a model i.e.

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

And it would fill Grid with rectangles of model data. And if there are more than let's say 6 items in model it would then fill other "page".

That's how it should look like: example

Currently I use StackLayout have 2 Grid items and Repeater inside of them and I divided my model into 2:

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

To fill each "page" with rectangles.

Writing logic to dynamically separate model into separate parts for each page seems overly complicated. I have tried GridView but I couldn't find important properties like in Grid:

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

Source of my example:

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

Upvotes: 0

Views: 1024

Answers (2)

derM
derM

Reputation: 13711

For a simple array, you can use the method array.slice(from, to) to create models for each page.

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

For QAbstractItemModel-descendents, you can use the method explained here if you want to have a QML-only solution.

Otherwise you might implement a faster filter model in C++ utilizing the QSortFilterProxyModel or maybe the QIdentityProxyModel

See this implementation by GrecKo for a possible way, how to get the SortFilterProxyModel working in QML.

Upvotes: 2

dtech
dtech

Reputation: 49329

You could try filtering the model to show only specific indices.

Or even simpler, you can simply set the delegate visibility depending on the index and items per page:

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

enter image description here

Upvotes: 2

Related Questions