Списки

Панель перегляду списку може спростити для вас динамічний показ багатьох компонентів.

Панелі списків можуть допомогти у показі об'єктів на основі моделі у привабливий спосіб. Щоб правильно користуватися панеллю списку, вам слід стежити за трьома речима:

  1. Моделлю, яка містить дані, які має бути показано на вашій панелі списку
  2. Делегата, який визначає, як буде показано кожне з елементів моделі
  3. Самої панелі списку, на якій буде показано відомості щодо моделі, відповідно до параметрів делегата

Якщо вам потрібні додаткові пояснення, у документації Qt є інформативна сторінка щодо цього питання.

Базові дані щодо моделей та панелей перегляду

У панелі списку є дві ключові властивості, на які нам слід звернути увагу:

  • model, яка приймає дані або id об'єкта, який містить дані
  • delegate, яка приймає компонент, якими ми скористаємося для показу даних у моделі

Модель є невидимою, оскільки вона лише містить дані. Типово, делегат буде загорнуто до Component, щоб його можна було використати повторно: він слугує як шаблон того, як створити екземпляр кожного делегата.

Тут наведено приклад, який містить точно одну панель перегляду списку, одну модель та один делегат, з використанням Kirigami.SubtitleDelegate:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    title: "List of Plasma products"
    width: 600
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            anchors.fill: parent
            model: plasmaProductsModel
            delegate: listDelegate
        }
        ListModel {
            id: plasmaProductsModel
            ListElement { product: "Plasma Desktop"; target: "desktop" }
            ListElement { product: "Plasma Mobile";  target: "mobile" }
            ListElement { product: "Plasma Bigscreen"; target: "TVs" }
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                text: `${model.product} is KDE software developed for ${model.target} stored at index ${model.index} of this list`
            }
        }
    }
}

І точно той самий приклад, вбудований:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    title: "List of Plasma products (inline)"
    width: 600
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            anchors.fill: parent
            model: ListModel {
                id: plasmaProductsModel
                ListElement { product: "Plasma Desktop"; target: "desktop" }
                ListElement { product: "Plasma Mobile";  target: "mobile" }
                ListElement { product: "Plasma Bigscreen"; target: "TVs" }
            }
            delegate: Controls.ItemDelegate {
                width: ListView.view.width
                text: `${model.product} is KDE software developed for ${model.target} stored at index ${model.index} of this list`
            }
        }
    }
}

Розбираємося із моделями

Модель містить дані, які буде використано для заповнення панелі перегляду списку. Для різних способів використання моделей передбачено різні способи доступу до даних:

СПОСІБ ВИКОРИСТАННЯДОСТУПУМОВИ ВИКОРИСТАННЯ
Моделі Qt із декількома ролямиmodel.index, model.someroleУ більшості випадків
Моделі Qt з однією роллюmodel.index, model.somerole, model.modelDataУ більшості випадків для прототипізації
Модель масиву JavaScriptmodel.index, model.modelDataДля прототипізації
Цілочисельна модельmodel.index, model.modelDataДля прототипізації

Ви можете ознайомитися із іншими способами використання моделей у документації Qt.

У наведеній вище таблиці «Моделі Qt» означають і C++-специфічні моделі, подібні до QAbstractListModel, і QML-специфічні моделі, зокрема ListModel. На цій сторінці підручника акцент зроблено на QML-специфічних моделях. Далі ми наведемо настанови щодо з'єднання моделей C++ із QML за допомогою QAbstractListModel.

Властивість model.index зроблено доступною для будь-якої моделі. Вона містить індекс (позиція) кожного делегата. Її можна скоротити до index для зручності.

Властивість model.якась_роль, про яку ми згадували вище, є лише замінником. Це не специфічна властивість, яка надходить від QML: записом якась_роль може бути будь-яка роль, яку визначено моделлю. У першому прикладі коду на цій сторінці, який показано над таблицею, модельplasmaProductsModel містить ролі product і target, доступ до яких можна здійснювати за допомогою model.product і model.target, відповідно.

Так само, як model.index можна скоротити до index, кожну властивість model.якась_роль можна скоротити до простого якась_роль (наприклад, product) для зручності, але рекомендуємо перетворювати їх до потрібних властивостей:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    title: "List of Plasma products (shortened with required properties)"
    width: 600
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            anchors.fill: parent
            model: plasmaProductsModel
            delegate: listDelegate
        }
        ListModel {
            id: plasmaProductsModel
            ListElement { product: "Plasma Desktop"; target: "desktop" }
            ListElement { product: "Plasma Mobile";  target: "mobile" }
            ListElement { product: "Plasma Bigscreen"; target: "TVs" }
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                required property string product
                required property string target
                required property int index
                text: `${product} is KDE software developed for ${target} stored at index ${index} of this list`
            }
        }
    }
}

Крім того, якщо модель містить лише одну роль або взагалі не містить ролі, доступ до даних також можна здійснювати за допомогою властивості model.modelData, що можна скоротити до modelData (і як така також має бути обов'язковою властивістю):

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami


Kirigami.ApplicationWindow {
    title: "List of KDE software"
    width: 400
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            anchors.fill: parent
            model: kdeSoftwareModel
            delegate: listDelegate
        }
        ListModel {
            id: kdeSoftwareModel
            ListElement { software: "Dolphin" }
            ListElement { software: "Discover" }
            ListElement { software: "KHelpCenter" }
            ListElement { software: "KCalc" }
            ListElement { software: "Ark" }
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                required property string modelData
                text: modelData // Це відповідає model.software
            }
        }
    }
}

Для порівняння, ось як наведених вище код міг би виглядати з масивом JavaScript, без ролі:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    title: "List of KDE software (as JS array)"
    width: 400
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            anchors.fill: parent
            model: ["Dolphin", "Discover", "KHelpCenter", "KCalc", "Ark"]
            delegate: listDelegate
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                required property string modelData
                text: modelData
            }
        }
    }
}

Використання цілого числа для моделі може бути корисним для дуже специфічних випадків, а саме, прототипізації та тестування:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    title: "Simple list of indexes"
    width: 400
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            anchors.fill: parent
            model: 30
            delegate: listDelegate
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                required property string modelData
                text: `This delegate's index is: ${modelData}`
            }
        }
    }
}

Розбираємося із переглядами і делегатами

Повернімося до початкового прикладу:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    title: "List of Plasma products"
    width: 600
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            // anchors.fill: parent
            model: plasmaProductsModel
            delegate: listDelegate
        }
        ListModel {
            id: plasmaProductsModel
            ListElement { product: "Plasma Desktop"; target: "desktop" }
            ListElement { product: "Plasma Mobile";  target: "mobile" }
            ListElement { product: "Plasma Bigscreen"; target: "TVs" }
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                text: `${model.product} is KDE software developed for ${model.target} stored at index ${model.index} of this list`
            }
        }
    }
}

На відміну від моделі (яка, в основному, містить дані) і компонента делегата (який з'являється, лише якщо створено екземпляр), панель перегляду є візуальним компонентом, екземпляр якого створюється негайно, і тому потребує або встановлення його розмірностей, або використання прив'язок чи компонувань.

Оскільки панелі перегляду є типово списками вмісту, які користувач міг би гортати, при їхньому додаванні до Kirigami.ScrollablePage, панелі перегляду стають переглядами основних даних із невеличкою фаскою навколо, і немає потреби заповнювати вмістом усю сторінку. Якщо панель перегляду додано до простої Kirigami.Page, доведеться встановлювати її розмірності належним чином, перш ніж її буде показано. Іншими словами, на панелі із гортанням вище anchors.fill: parent є необов'язковим; якщо було б використано просту сторінку, ця інструкція була б обов'язковою.

Можна використовувати декілька програмних інтерфейсів панелей перегляду, деякі походять з Qt, а деякі — з Kirigami. Ось найпоширеніші:

Для делегата, з іншого боку, завжди має бути встановлено розмірності. Загалом, його розмірності буде встановлено лише так, щоб використовувати усю ширину панелі перегляду.

Найпоширенішим використанням делегата є використання у межах Component, що не створює екземпляра делегата негайно. При побудові панелі перегляду делегат буде використано як шаблон для створення усіх елементів на панелі перегляду.

Хоча ви ви можете створювати власні нетипові компоненти, які буде використано як делегати без специфічних для делегата програмних інтерфейсів Qt (наприклад, компонування, що містить небагато записів Item), QtQuick Controls надає у ваше розпорядження програмні інтерфейси, якими простіше скористатися:

  • ItemDelegate (делегати, які містять лише текст)
  • CheckDelegate (делегати з пунктом із позначкою)
  • RadioDelegate (делегати із варіантом вибору)
  • SwitchDelegate (делегати з перемикачем)
  • SwipeDelegate (делегати, над якими можна проводити пальцем)

Вам слід надавати перевагу використанню делегатів основної бібліотеки Qt там, де це можливо.

Над цими делегатами Qt Kirigami надає у ваше розпорядження власні еквіваленти із доданими функціональними можливостями підзаголовків і піктограм:

Елементи програмного інтерфейсу, назви яких завершуються на «Delegate», можна встановлювати як безпосередні делегати панелі перегляду, як у попередніх прикладах, де використано Controls.ItemDelegate:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami
import org.kde.kirigami.delegates as KD

Kirigami.ApplicationWindow {
    title: "List of Plasma products"
    width: 600
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            model: plasmaProductsModel
            delegate: listDelegate
        }
        ListModel {
            id: plasmaProductsModel
            ListElement { product: "Plasma Desktop"; target: "desktop" }
            ListElement { product: "Plasma Mobile";  target: "mobile" }
            ListElement { product: "Plasma Bigscreen"; target: "TVs" }
        }
        Component {
            id: listDelegate
            KD.CheckSubtitleDelegate {
                width: ListView.view.width
                text: `${model.product} is KDE software developed for ${model.target}.`
                subtitle: `This delegate is stored at index ${model.index} of this list`
                icon.name: "kde"
            }
        }
    }
}

Обидва, TitleSubtitle і IconTitleSubtitle, вважаються такими, які слід використовувати для перевизначення contentItem делегата Qt, приклад:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami
import org.kde.kirigami.delegates as KD

Kirigami.ApplicationWindow {
    title: "List of Plasma products"
    width: 600
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            // anchors.fill: parent
            model: plasmaProductsModel
            delegate: listDelegate
        }
        ListModel {
            id: plasmaProductsModel
            ListElement { product: "Plasma Desktop"; target: "desktop" }
            ListElement { product: "Plasma Mobile";  target: "mobile" }
            ListElement { product: "Plasma Bigscreen"; target: "TVs" }
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                text: `${model.product} is KDE software developed for ${model.target}.`
                contentItem: KD.IconTitleSubtitle {
                    title: parent.text
                    subtitle: `This delegate is stored at index ${model.index} of this list`
                    icon.name: "kde"
                }
            }
        }
    }
}

Із практичним прикладом використання делегатів Kirigami можна ознайомитися у файлі ListItemTest у сховищі Kirigami.