Pogledi seznama
Pregledi seznamov Listviews vam lahko pomagajo prikazati predmete iz modela na privlačen način. Če želite uporabiti pogled seznama, morate spremljati tri stvari:
- model, ki vsebuje podatke, ki jih želite prikazati v pogledu seznama
- delegat, ki določa, kako bo vsak element v modelu prikazan
- Sam pogled seznama, ki bo prikazoval informacije iz modela v skladu z delegatom
Če želite dodatno pojasnilo, ima dokumentacija Qt informativna stran na to temo.
Osnove modelov in pogledov
Seznamski pogled ima dve bistveni lastnosti, na kateri moramo biti pozorni:
- model, ki sprejema podatke ali 'id' predmeta, ki nosi podatke
- delegate, ki sprejema komponento, ki jo bomo uporabili za prikaz podatkov v modelu
Model ni viden, saj vsebuje le podatke. Običajno bo delegat zavit v komponento, tako da jo je mogoče ponovno uporabiti: služi kot načrt za instanciranje vsakega delegata.
Tukaj je primer, ki vsebuje natanko en pogled seznama, en model in enega delegata z uporabo 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`
}
}
}
}
In popolnoma enak primer, v vrstici:
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`
}
}
}
}
Razumevanje modelov
Model vsebuje podatke, ki bodo uporabljeni za zapolnitev pogleda seznama. Različni načini uporabe modelov imajo različne načine za dostop do podatkov:
NAČIN UPORABE | KAKO DOSTOPATI | KDAJ UPORABITI |
---|---|---|
Modeli Qt z več kot eno vlogo | model.index, model.somerole | V večini primerov |
Modeli Qt z eno vlogo | model.index, model.somerole, model.modelData | V večini primerov, za izdelavo prototipov |
JavaScript array model | model.index, model.modelData | Za izdelavo prototipov |
Celoštevilski model | model.index, model.modelData | Za izdelavo prototipov |
O drugih načinih uporabe modelov lahko preberete v dokumentaciji Qt.
V zgornji tabeli se "modeli Qt" nanašajo tako na modele, specifične za C++, kot je QAbstractListModel, kot na modele, specifične za QML, kot je ListModel. Ta stran učbenika se bo osredotočila samo na modele, specifične za QML. Malo naprej nudimo učbenik za Povezovanje modelov C++ z QML z uporabo QAbstractListModel.
Lastnost model.index
je na voljo vsakemu modelu in vsebuje indeks (položaj) vsakega delegata. Zaradi udobja ga je mogoče skrajšati na index
.
Zgoraj omenjena lastnost model.somerole
je le označba mesta in ni specifična lastnost, ki izhaja iz QML: somerole
je lahko katera koli vloga, ki jo definira model. V prvem primeru kode te strani, ki je prikazan nad tabelo, ima model plasmaProductsModel
vlogi product
in target
, do katerih lahko dostopate z model.product
oziroma model.target
.
Tako kot je model.index
mogoče skrajšati v index
, lahko vsako lastnost model.somerole
skrajšamo samo v somerole
(kot product
) zaradi udobja, vendar je priporočljivo, da jih spremenite v zahtevane lastnosti :
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`
}
}
}
}
Poleg tega, če model vsebuje samo eno vlogo ali sploh nima nobene vloge, je mogoče do njegovih podatkov dostopati tudi z lastnostjo model.modelData
, ki jo je mogoče tudi skrajšati v modelData
(in kot taka bi morala biti tudi zahtevana lastnost):
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 // To se ujema z model.software
}
}
}
}
Za primerjavo, tukaj je videti zgornja koda s poljem JavaScripta, brez vloge:
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
}
}
}
}
Uporaba celega števila za model je lahko uporabna za zelo specifične primere, namreč izdelavo prototipov in teste:
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}`
}
}
}
}
Razumevanje pogledov in delegatov
Vrnimo se k izvirnemu primeru:
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`
}
}
}
}
Za razliko od modela (ki vsebuje samo podatke) in delegata Component (ki se prikaže le, ko je instanciran), je pogled vizualna komponenta, ki je takoj instancirana, zato mora imeti bodisi nastavljene dimenzije ali uporabite sidra ali postavitve.
Ker so pogledi običajno seznami vsebine, po kateri bi se uporabnik rad pomikal, ko so dodani na Kirigami.ScrollablePage, pogledi postanejo glavna vsebina z malo oblazinjenja okoli njih in ni potrebe da zapolni stran. Ko je pogled dodan k preprosti strani Kirigami.Page, bo moral pravilno nastaviti svoje dimenzije, preden se prikaže. Z drugimi besedami: na zgornji strani, po kateri se lahko premikate, anchors.fill: parent
ni zahtevan; če je bila uporabljena preprosta stran, pa bi bil zahtevan.
Uporabiti je mogoče več pogledov API-jev, nekatere iz Qt in nekatere iz Kirigami. Tu so najpogosteje uporabljeni:
- Qt's ListView
- Qt's GridView
- Qt's TableView
- Qt's TreeView
- Kirigami's CardsListView
- Kirigami's ColumnView
Po drugi strani mora imeti delegat vedno nastavljene dimenzije. Na splošno so njegove mere nastavljene tako, da uporabljajo samo celotno širino pogleda.
Pogoste napake
Zgoraj navedeno pomeni, da delegati ne bi smeli imeti spodnjih sider, saj ni treba, da ima delegat enako višino kot pogled. Z drugimi besedami, verjetno ne boste nikoli želeli uporabiti anchors.fill: parent
.
Poleg tega je možno nastaviti njegove dimenzije s pomočjo nadrejenega elementa in sider, ki je običajno pogled contentItem, takole:
Controls.ItemDelegate {
anchors.left: parent.left
anchors.right: parent.right
text: // ...
}
Ni zagotovljeno, da bo nadrejeni element delegata pogled, zato se mu je treba izogibati. Namesto tega uporabite priloženo lastnost ListView.view, da pokažete na nadrejeni pogled delegata:
Controls.ItemDelegate {
width: ListView.view.width
text: // ...
}
Najpogostejša uporaba delegata je znotraj komponente, ki delegata ne instancira takoj. Ko je pogled izdelan, se delegat nato uporabi kot načrt za izdelavo vsakega elementa v pogledu.
Medtem ko lahko naredite svoje komponente po meri, ki jih boste uporabljali kot delegate brez API-jev Qt, specifičnih za delegate (na primer postavitev, ki vsebuje nekaj elementov), QtQuick Controls ponuja API-je za delegate, ki so preprostejši za uporabo:
- ItemDelegate (delegati samo z besedilom)
- CheckDelegate (delegati s potrditvenim poljem)
- RadioDelegate (delegati z radijem)
- SwitchDelegate (delegati s stikalom)
- SwipeDelegate (delegati, ki jih je mogoče povleči)
Če je mogoče, raje uporabite delegate iz Qt toka navzgor.
Poleg teh delegatov Qt ponuja Kirigami svoje ekvivalente z dodano funkcijo podnapisov in ikon:
- TitleSubtitle
- IconTitleSubtitle
- SubtitleDelegate
- CheckSubtitleDelegate
- RadioSubtitleDelegate
- SwitchSubtitleDelegate
API, ki se konča z "Delegate", lahko nastavite kot neposrednega delegata pogleda, tako kot v prejšnjih primerih, ki so uporabljali 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"
}
}
}
}
Tako TitleSubtitle kot IconTitleSubtitle naj bi se uporabljala za preglasitev contentItem delegata Qt, na primer:
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"
}
}
}
}
}
Praktični primer uporabe delegatov Kirigami si lahko ogledate v datoteki ListItemTest v repozitoriju Kirigami.