Vistes de llista
Les vistes de llista «Listviews» poden ajudar a mostrar objectes d'un model d'una manera atractiva. Per a utilitzar una vista de llista, haureu de realitzar un seguiment de tres coses:
- El model, el qual conté les dades que voleu mostrar a la vista de llista.
- El delegat, el qual defineix com es mostrarà cada element en el model.
- La vista de llista en si, la qual mostrarà la informació del model segons el delegat.
Per a més aclariments, la documentació de les Qt té una pàgina informativa sobre el tema.
Essencials de models i vistes
Una vista de llista té dues propietats essencials a les quals hem de parar atenció:
- model, el qual accepta les dades o l'
id
de l'objecte que conté les dades - delegate, el qual accepta el component que utilitzarem per a mostrar les dades en el model
El model no és visible, ja que només conté dades. Normalment, el delegat s'embolcallarà en un Component perquè sigui reutilitzable: serveix com a esquema per a conèixer com instanciar cada delegat.
Aquí hi ha un exemple que conté exactament una vista de llista, un model i un delegat, utilitzant un 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`
}
}
}
}
I el mateix exemple, en línia:
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`
}
}
}
}
Entendre els models
El model conté les dades que s'utilitzaran per a emplenar la vista de llista. Les maneres diferents d'utilitzar els models tenen maneres diferents d'accedir a les dades:
MANERA D'UTILITZAR | COM ACCEDIR-HI | QUAN EMPRAR-HO |
---|---|---|
Models Qt amb més d'un rol | model.index, model.somerole | En la majoria dels casos |
Models Qt amb un rol | model.index, model.somerole, model.modelData | En la majoria dels casos, per a fer prototips |
Model de matriu JavaScript | model.index, model.modelData | Per a fer prototips |
Model enter | model.index, model.modelData | Per a fer prototips |
Podeu llegir sobre altres maneres d'usar els models a la documentació de les Qt.
A la taula anterior, els «models Qt» es refereixen tant a models específics de C++ com QAbstractListModel i a models específics de QML com ListModel. Aquesta pàgina de la guia d'aprenentatge només se centrarà en models específics de QML. Més endavant, proporcionem una guia d'aprenentatge per a Connectar models C++ a QML utilitzant QAbstractListModel.
La propietat model.index
es posa a disposició de cada model i conté l'índex (la posició) de cada delegat. Es pot escurçar a index
per comoditat.
La propietat model.somerole
esmentada anteriorment és només una variable de substitució, no és una propietat específica que prové del QML: somerole
pot ser qualsevol rol que estigui definit pel model. En el primer exemple de codi d'aquesta pàgina que es mostra a sobre de la taula, el model plasmaProductsModel
té els rols product
i target
, als quals es pot accedir amb model.product
i model.target
, respectivament.
De la mateixa manera que model.index
es pot escurçar a index
, cada propietat model.somerole
es pot escurçar a només somerole
(com product
) per comoditat, però es recomana que es converteixin en propietats requerides:
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`
}
}
}
}
A més, si el model conté només un rol o no té cap rol, també es pot accedir a les seves dades amb la propietat model.modelData
, que també es pot escurçar a modelData
(i com a tal també necessitaria ser una propietat requerida):
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 // Aquest coincideix amb model.software
}
}
}
}
Com a comparació, aquí és com es veuria el codi anterior amb una matriu JavaScript, sense 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
}
}
}
}
L'ús d'un enter per al model pot ser útil per a casos molt específics, com el prototipatge i les proves:
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}`
}
}
}
}
Entendre les vistes i els delegats
Tornem a l'exemple original:
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`
}
}
}
}
A diferència del model (que només conté dades) i d'un delegat Component (que només apareixen quan s'instancien), la vista és un component visual instanciat immediatament i, per tant, necessita tenir les seves dimensions establertes o utilitzar ancoratges o disposicions.
Com que les vistes són normalment llistes de contingut per les quals l'usuari es desplaçarà, quan s'afegeixen a un Kirigami.ScrollablePage, les vistes es converteixen en el contingut principal amb poc farciment al voltant d'elles, i no hi ha cap necessitat de fer que ompli la pàgina. Quan la vista s'afegeix a una única Kirigami.Page, necessitarà establir les seves dimensions correctament abans que aparegui. En altres paraules: a la pàgina desplaçable de dalt, no es requereix anchors.fill: parent
; si s'utilitzés una única pàgina, seria necessària.
Hi ha diverses API de vistes que es poden utilitzar, algunes de les Qt i altres de Kirigami. A continuació us detallem les més utilitzades:
- ListView de les Qt
- GridView de les Qt
- TableView de les Qt
- TreeView de les Qt
- CardsListView del Kirigami
- ColumnView del Kirigami
D'altra banda, el delegat sempre ha de tenir les seves dimensions establertes. Generalment, les seves dimensions s'estableixen per a utilitzar només l'amplada completa de la vista.
Errors habituals
L'anterior significa que els delegats no haurien de tenir àncores inferiors, ja que el delegat no necessita tenir la mateixa alçada que la vista. En altres paraules, probablement mai voldreu utilitzar anchors.fill: parent
.
A més, encara que és possible establir les seves dimensions utilitzant el pare i les àncores, que normalment és el «contentItem» de la vista, així:
Controls.ItemDelegate {
anchors.left: parent.left
anchors.right: parent.right
text: // ...
}
No està garantit que el pare del delegat sigui una vista, per tant, això ha d'evitar-se. En lloc d'això, utilitzeu la propietat adjunta ListView.view per a apuntar a la vista pare del delegat:
Controls.ItemDelegate {
width: ListView.view.width
text: // ...
}
L'ús més comú d'un delegat es troba dins d'un Component, que no instancia el delegat immediatament. Quan es construeix una vista, el delegat s'utilitza com a esquema per a fer cada element a la vista.
Tot i que podeu crear els vostres propis components personalitzats per a ser utilitzats com a delegats sense les API de les Qt específiques de delegats (per exemple, una disposició que conté alguns elements), els QtQuick Controls proporcionen les API de delegats que són més senzilles d'utilitzar:
- ItemDelegate (delegats amb només text)
- CheckDelegate (delegats amb una casella de selecció)
- RadioDelegate (delegats amb una opció)
- SwitchDelegate (delegats amb un commutador)
- SwipeDelegate (delegats que es poden lliscar)
Hauríeu de preferir utilitzar els delegats originals de les Qt quan sigui possible.
A sobre d'aquests delegats de les Qt, el Kirigami proporciona els seus propis equivalents, amb la funcionalitat afegida de subtítols i icones:
- TitleSubtitle
- IconTitleSubtitle
- SubtitleDelegate
- CheckSubtitleDelegate
- RadioSubtitleDelegate
- SwitchSubtitleDelegate
L'API que acaba amb «Delegate» es pot definir com un delegat directe de la vista, igual que els exemples anteriors que utilitzaven 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"
}
}
}
}
Tant TitleSubtitle com IconTitleSubtitle s'espera que s'utilitzin per a substituir el «contentItem» d'un delegat de les Qt, per exemple:
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"
}
}
}
}
}
Es pot veure un exemple pràctic d'ús dels delegats del Kirigami al fitxer ListItemTest al repositori del Kirigami.