ListModel をある単位で分割したモデルを利用したい

年に一回くらいの頻度で ListView を使うけれど1画面に表示するアイテムの数は固定で SwipeView で複数ページに分けたい と思うことがあります。

ListView で縦スクロールするのではなく、SwipeView の横スクロールで表示を切り替えるってことです。

様々な理由で、おおもとのモデルは1元管理したい(もしくはしなければならない)ことが多いため、それをソースとする ProxyModel を作るのがよさそうです。

作ってみた

ソースコードは https://github.com/task-jp/paginationproxymodel を参照してください。

QML で ListModel のデータを、PagenationProxyModel というプロキシモデルでページ単位に分割しています。

import QtQuick 2.12
import QtQuick.Controls 2.5
import PaginationProxyModel 2.15

ApplicationWindow {
    width: 320
    height: 480
    visible: true
    title: 'PaginationProxyModel'

    ListModel {
        id: items
        readonly property int countPerPage: 10
        readonly property int pageCount: Math.floor((items.count + items.countPerPage - 1) / items.countPerPage)
        Component.onCompleted: {
            for (var i = 0; i < 21; i++)
                items.append( { "text": 'Item at %1'.arg(i) })
        }
    }

    SwipeView {
        id: swipeView
        anchors.fill: parent
        currentIndex: tabBar.currentIndex

        Repeater {
            model: items.pageCount
            Item {
                id: delegate
                property int index: model.index
                ListView {
                    id: listView
                    anchors.fill: parent
                    interactive: false
                    model: PaginationProxyModel {
                        source: items
                        page: delegate.index
                        countPerPage: items.countPerPage
                    }
                    delegate: Text {
                        width: ListView.view.width
                        height: ListView.view.height / items.countPerPage
                        text: model.text
                        verticalAlignment: Qt.AlignVCenter
                    }
                }
            }
        }
    }

    footer: TabBar {
        id: tabBar
        currentIndex: swipeView.currentIndex

        Repeater {
            model: items.pageCount
            TabButton {
                text: qsTr("Page %1").arg(model.modelData)
            }
        }
    }
}

PagenationProxyModel の設計

おおもとのモデルに QIdentityProxyModel でページの情報を追加し、それを QSortFilterProxyModel でフィルタリングをしています。本当は両者の機能(からソートを除いた)専用のモデルを書くべきですが、それは今後の課題とします。