Lijstweergaven
Listviews kan u helpen om objecten uit een model op een attractieve manier te tonen. Om een lijstweergave te gebruiken moet u drie dingen volgen:
- Het model, dat de gegevens bevat die u in uw lijstweergave wilt tonen
- De delegate, die definieert hoe elk element in het model getoond zal worden
- De list view zelf, die de informatie uit het model volgens de delegate zal tonen
Als u verdere verheldering wilt, de Qt-documentatie heeft een informatieve pagina over het onderwerp.
Essenties van modellen en weergaven
Een lijstweergave heeft twee essentiële eigenschappen waar we aandacht aan moeten besteden:
- model, die de gegevens accepteert of de
id
van het object dat de gegevens bevat - delegate, die de component accepteert die we willen gebruiken om de gegevens in het model te tonen
Het model wordt niet getoond, omdat het alleen data bevat. Standaard wordt de delegatie ingepakt in een component zodat het herbruikbaar is: het dient als blauwdruk voor hoe een delegatie moet worden gecreëerd.
Hier is een voorbeeld met precies een weergeven lijst, een model en een delegatie, dat een Kirigami.SubtitleDelegate gebruikt:
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`
}
}
}
}
En precies hetzelfde voorbeeld, inline:
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`
}
}
}
}
Modellen begrijpen
In het model is de data dat wordt gebruikt om dat zal worden gebruikt om de getoonde lijst te bevolken. De verschillende manieren om de modellen te gebruiken hebben verschillende manieren om toegang te krijgen tot de data:
HOE TE GEBRUIKEN | HOE TOEGANG TE KRIJGEN | WANNEER TE GEBRUIKEN |
---|---|---|
Qt modellen met meer dan een rol | model.index, model.somerole | Voor de meeste gevallen |
Qt modellen met een rol | model.index, model.somerole, model.modelData | In de meeste gevallen, voor prototyping |
JavaScript array model | model.index, model.modelData | Voor prototyping |
Integer model | model.index, model.modelData | Voor prototyping |
U kunt lezen over andere manieren om modellen te gebruiken in de Qt documentatie.
In de tabel hierboven,verwijst "Qt modellen" naar zowel C++-specifieke modellen zoals QAbstractListModel als naar QML-specifieke modellen zoals ListModel. Deze pagina zal zich alleen focussen op QML-specifieke modellen. Verderop geven we een instructie voor het verbinden van C++ modellen met QML met gebruik van QAbstractListModel.
De model.index
-eigenschap is bij elk model beschikbaar en heeft de index index (de positie) van elk delegate. Voor de handigheid kan het worden afgekort naar index
.
De eigenschap model.somerole
hierboven genoemd is alleen maar een plaatshouder, het is niet een specifieke eigenschap die uit QML komt : somerole
kan elke rol zijn die door het model wordt gedefinieerd. In het eerste code voorbeeld op deze pagina toont de tabel hierboven, het model plasmaProductsModel
heeft de product
en target
rollen, waar toe met respectievelijk model.product
en model.target
toegang gekregen kan worden.
Net zoals model.index
afgekort kan worden tot index
, kan voor de handigheid ook elk de model.somerole
-eigenschap afgekort worden tot alleen maar somerole
(zoals product
), maar het wordt aanbevolen dat ze naar de betreffende eigenschappen worden omgezet:
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`
}
}
}
}
Daarnaast, als het model alleen maar een rol heeft of helemaal geen rol heeft, dan kan men er ook toegang toe krijgen met de eigenschap model.modelData
, wat ook afgekort kan worden tot modelData
(en als zodanig een vereiste eigenschap moet zijn):
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 // Dit komt overeen met model.software
}
}
}
}
Voor vergelijking, is hier hoe de code van boven er uit zou zien met een JavaScript array, zonder een rol:
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
}
}
}
}
Het gebruik van een integer voor de rol kan in zeer specifieke gevallen bruikbaar zijn, namelijk prototyping en tests:
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}`
}
}
}
}
Weergaven en delegaties begrijpen
Laten we terug gaan naar het oorspronkelijke voorbeeld:
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`
}
}
}
}
In tegenstelling tot het model (wat alleen maar data bevat) en een delegatie Component (wat alleen verschijnt als het gecreëerd wordt), is de weergave een visueel component dat onmiddellijk wordt gecreëerd en er moet daarom daarvan zijn afmetingen ingesteld zijn of er moeten anchors gebruikt worden of er moeten Layouts (vensterindelingen) gebruikt worden .
Omdat weergaven meestal lijsten met inhoud zijn waar de gebruiker doorheen wil scrollen, als ze aan een Kirigami.ScrollablePage zijn toegevoegd, dan vormen de weergaven de hoofdinhoud met weinig ruimte daaromheen, en het is daarom niet noodzakelijk dat het de hele pagina vult. Als de weergave wordt toegevoegd aan een eenvoudige Kirigami.Page, dan is het noodzakelijk dat de afmetingen daarvan correct zijn ingesteld voordat het getoond wordt. Met andere woorden: in de scrollable pagina hierboven, is anchors.fill: parent
niet nodig; maar als een eenvoudige pagina wordt gebruikt dan is het wel vereist.
Er zijn meerdere weergave-API's die kunnen worden gebruikt, enkele van Qt en enkele van Kirigami. Hier zijn de meest voorkomende:
- Qt's ListView
- Qt's GridView
- Qt's TableView
- Qt's TreeView
- Kirigami's CardsListView
- Kirigami's ColumnView
Daarentegen moet bij een delegatie altijd de afmetingen opgegeven worden. Meestal worden de afmetingen daarvan zodanig ingesteld dat het alleen de volledige breedte van het venster gebruikt.
Vaak gemaakte fouten
Bovengenoemde houdt in dat gedelegeerden geen ankers onderaan zouden moeten hebben, omdat de gedelegeerde niet dezelfde hoogte hoeft te hebben als het venster. Met andere woorden, u zal waarschijnlijk nooit anchors.fill: parent
willen gebruiken.
Daarbij, ofschoon het mogelijk is om de afmetingen daarvan in te stellen door gebruik van de parent en ankers, wat is meestal de contentItem van de weergave, zoals op deze manier:
Controls.ItemDelegate {
anchors.left: parent.left
anchors.right: parent.right
text: // ...
}
Er is geen garantie dat de parent van de gedelegeerde een weergave heeft en moet daarom vermeden worden. Gebruik in plaats daarvan ListView.view verbonden eigenschap dat verwijst naar de weergave van de parent van de gedelegeerde:
Controls.ItemDelegate {
width: ListView.view.width
text: // ...
}
Een gedelegeerde word het meest gebruikt in een Component, die de gedelegeerde niet onmiddellijk word gecreëerd. Als een weergave word geconstrueerd, dan word de gedelegeerden gebruikt als een blauwdruk voor elk item in de weergave.
Ofschoon aangepaste componenten gemaakt kunnen worden die als gedelegeerden zonder gedelegeerde-specifieke Qt APIs (bijvoorbeeld een Layout met alleen een paar items) gebruikt kunnen worden, heeft QtQuick Controls gedelegeerde (delegate)-API's die eenvoudig te gebruiken zijn:
- ItemDelegate (delegeert met alleen tekst)
- CheckDelegate ((delegeert met een keuzevakje)
- RadioDelegate (delegeert met een keuzerondje)
- SwitchDelegate (delegeert met een schakelaar)
- SwipeDelegate (gedelegeerde dat weggeveegd kan worden)
Het is raadzaam om waar mogelijk de upstream Qt gedelegeerden te gebruiken.
Bovenop deze Qt gedelegeerden heeft Kirigami zijn eigen equivalenten, met de extra functionaliteit van subtitel en pictogrammen:
- TitleSubtitle
- IconTitleSubtitle
- SubtitleDelegate
- CheckSubtitleDelegate
- RadioSubtitleDelegate
- SwitchSubtitleDelegate
De API die eindigt met "Delegate" kan ingesteld worden als een direct gedelegeerde van de weergave, net zoals in de vorige voorbeelden die Controls.ItemDelegate gebruiken:
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"
}
}
}
}
Er wordt verwacht dat zowel TitleSubtitle als IconTitleSubtitle worden gebruikt om een Qt delegate's contentItem te overschrijven, als voorbeeld:
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"
}
}
}
}
}
Een praktisch voorbeeld van het gebruik van Kirigami gedelegeerden is te vinden in het ListItemTest-bestand in de Kirigami Repository.