Vistes de llista
Les List views 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'
idde 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.