Компонент Qt, который будет брать модель и отображать ее в сетке, разделенной на страницы

Я хочу создать многоразовый компонент, в котором я мог бы передать модель, т.е.

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

И это заполнило бы Grid прямоугольниками данных модели. И если в модели больше, чем, скажем, 6 элементов, она заполнит другую «страницу».

Вот как это должно выглядеть: example

В настоящее время я использую 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
    }
}

person Eligijus Pupeikis    schedule 19.09.2017    source источник
comment
Вы хотите, чтобы модель была массивом или ListModel?   -  person derM    schedule 19.09.2017
comment
Массив @derM. Думаю, ListModel будет еще сложнее.   -  person Eligijus Pupeikis    schedule 19.09.2017
comment
Что ж, вы можете использовать решение из здесь хотя... Я написал его вскоре после того, как начал работать с QML, и есть что улучшить. Использование DelegateModel может быть быстрее, если вы замените его на C++ ...ProxyModel, например QSortFilterProxyModel, или модель не-так-идентичности-прокси, но для последнего требуется ListModel afaik.   -  person derM    schedule 19.09.2017


Ответы (2)


Для простого массива вы можете использовать метод array.slice(from, to)< /a> для создания моделей для каждой страницы.

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-потомков вы можете использовать описанный метод здесь, если вы хотите иметь решение только для QML.

В противном случае вы могли бы реализовать более быструю модель фильтра на C++, используя QSortFilterProxyModel или, возможно, QIdentityProxyModel

См. эту реализацию GrecKo для возможного Кстати, как заставить SortFilterProxyModel работать в QML.

person derM    schedule 19.09.2017
comment
slice офк. Моя вина :-) - person derM; 19.09.2017

Вы можете попробовать отфильтровать модель, чтобы показать только определенные индексы.

Или, что еще проще, вы можете просто установить видимость делегата в зависимости от индекса и элементов на странице:

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

введите здесь описание изображения

person dtech    schedule 19.09.2017
comment
Любите решение. Мне не понравилось, что я использовал StackLayout, так что это именно то, что я искал. - person Eligijus Pupeikis; 19.09.2017
comment
Для небольших моделей это простое решение. Для больших моделей у вас будут огромные накладные расходы Rectangles. - person derM; 19.09.2017
comment
Repeater всегда создает все экземпляры. Grid просто игнорирует все Item без размеров или видимости для своего макета. - person derM; 19.09.2017
comment
(из документации) Если элемент в Сетка не видна, или если она имеет ширину или высоту 0, элемент не будет размещен и не будет виден в столбце. Вы можете изменить Grid на GridView и разделить contentItem на показывать всегда правую часть. - person derM; 19.09.2017
comment
Да, я быстро проверил, и это действительно так. Все элементы созданы. Тем не менее, идеально подходит для моделей, которые не являются огромными. В реальном производстве я использую свою собственную прокси-модель, которую можно фильтровать и сортировать с помощью функторов JS. - person dtech; 19.09.2017
comment
Полностью согласен с этим! - person derM; 19.09.2017
comment
Решение derM действительно является правильным решением по причинам, упомянутым выше. - person Eligijus Pupeikis; 19.09.2017
comment
У него есть собственные накладные расходы — каждый раз, когда модель изменяется, все элементы делегата будут создаваться заново, используя больше ЦП. И из-за паршивого управления памятью QML использование памяти, вероятно, превысит наличие всех объектов в памяти, если только вы не имеете дело с очень большим количеством элементов, например, с тысячами и тысячами элементов. - person dtech; 19.09.2017