Skip to main content
Passa al contenuto

Viste a elenco

Una vista a elenco può aiutarti a visualizzare facilmente molti componenti in maniera dinamica.

Visualizzazioni elenco può aiutarti a visualizzare gli oggetti da un modello in modo attraente. Per utilizzare una visualizzazione elenco, devi tenere traccia di tre cose:

  1. Il modello, che contiene i dati che vuoi visualizzare nella vista a elenco
  2. Il delegato, che definisce come verrà visualizzato ciascun elemento del modello
  3. La vista a elenco stessa, che visualizza le informazioni dal modello secondo il delegato

Se desideri ulteriori chiarimenti, la documentazione Qt contiene una pagina informativa sull'argomento.

Elementi essenziali di modelli e viste

Una vista a elenco ha due proprietà essenziali a cui devi prestare attenzione:

  • model, che accetta i dati o l'"id" dell'oggetto che contiene i dati
  • delegate, che accetta il componente che utilizzeremo per visualizzare i dati nel modello

Il modello non è visibile poiché contiene solo dati. In genere il delegato verrà racchiuso in un componente in modo che sia riutilizzabile: funge da modello su come creare un'istanza di ciascun delegato.

Ecco un esempio che contiene esattamente una visualizzazione elenco, un modello e un delegato, utilizzando 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`
            }
        }
    }
}

E lo stesso identico esempio, in linea:

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`
            }
        }
    }
}

Capire i modelli

Il modello contiene i dati che verranno utilizzati per popolare la visualizzazione elenco. Modi diversi di utilizzare i modelli comportano modi diversi di accedere ai dati:

MODO D'USOCOME ACCEDEREQUANDO USARE
Modelli Qt con più di un ruolomodel.index, model.someroleNella maggior parte dei casi
Modelli Qt con un ruolomodel.index, model.somerole, model.modelDataNella maggior parte dei casi, per la prototipazione
Modello di array JavaScriptmodel.index, model.modelDataPer la prototipazione
Modello interomodel.index, model.modelDataPer la prototipazione

Puoi leggere informazioni su altri modi per utilizzare i modelli nella documentazione Qt.

Nella tabella sopra, "modelli Qt" si riferisce sia a modelli specifici di C++ come QAbstractListModel sia a modelli specifici di QML come ListModel. Questa pagina del tutorial si concentrerà solo sui modelli specifici di QML. Più avanti verrà fornito un tutorial per Connettere modelli C++ a QML utilizzando QAbstractListModel.

La proprietà model.index è resa disponibile a ogni modello e contiene l'indice (la posizione) di ciascun delegato. Può essere abbreviato in "indice" per comodità.

La proprietà model.somerole menzionata sopra è solo un segnaposto, non è una proprietà specifica che proviene da QML: somerole può essere qualsiasi ruolo definito dal modello. Nel primo esempio di codice di questa pagina mostrato sopra la tabella, il modello plasmaProductsModel ha i ruoli "product" e "target", a cui è possibile accedere rispettivamente con "model.product" e "model.target".

Proprio come "model.index" può essere abbreviato in "index", ogni proprietà "model.somerole" può essere abbreviata semplicemente in "somerole" (come "product") per comodità, ma si consiglia di trasformarle in proprietà richieste:

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`
            }
        }
    }
}

Inoltre, se il modello contiene un solo ruolo o non ne ha alcuno, è possibile accedere ai suoi dati anche con la proprietà "model.modelData", che può anche essere abbreviata in "modelData" (e come tale dovrebbe anche essere una proprietà obbligatoria):

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 // Questo corrisponde a model.software
            }
        }
    }
}

Per confronto, ecco come apparirebbe il codice precedente con un array JavaScript, senza ruolo:

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'utilizzo di un numero intero per il modello può essere utile per casi molto specifici, ovvero prototipazione e test:

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}`
            }
        }
    }
}

Capire le viste e i delegati

Torniamo all'esempio iniziale:

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: genitore
            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 differenza del modello (che contiene semplicemente dati) e di un delegato Component (che appare solo quando istanziato), la vista è un componente visivo istanziato immediatamente e quindi deve avere le sue dimensioni impostate o utilizzare ancore o layout.

Poiché le visualizzazioni sono comunemente elenchi di contenuti che l'utente vorrebbe scorrere, quando vengono aggiunte a una Kirigami.ScrollablePage, le visualizzazioni diventano il contenuto principale con poca imbottitura attorno ad esse e non è necessario farle riempire la pagina. Quando la vista viene aggiunta a una semplice Kirigami.Page, sarà necessario impostarne correttamente le dimensioni prima di essere visualizzata. In altre parole: nella pagina scorrevole sopra, anchors.fill: parent non è richiesto; se fosse utilizzata una pagina semplice, sarebbe necessaria.

È possibile utilizzare più API di visualizzazione, alcune da Qt e altre da Kirigami. Ecco quelli più comunemente usati:

  • ListView di Qt
  • [GridView] di Qt(docs:qtquick;QtQuick.GridView)
  • [TableView] di Qt(docs:qtquick;QtQuick.TableView)
  • [TreeView] di Qt(docs:qtquick;QtQuick.TreeView)
  • [CardsListView] di Kirigami(docs:kirigami;org.kde.kirigami.CardsListView)
  • [ColumnView] di Kirigami(docs:kirigami;org.kde.kirigami.layouts.ColumnView)

Il delegato invece deve sempre avere le sue dimensioni impostate. Generalmente le sue dimensioni sono impostate per utilizzare solo l'intera larghezza della vista.

L'uso più comune di un delegato è all'interno di un Component, che non istanzia immediatamente il delegato. Quando viene costruita una vista, il delegato viene quindi utilizzato come modello per creare ogni elemento nella vista.

Sebbene sia possibile creare componenti personalizzati da utilizzare come delegati senza API Qt specifiche del delegato (ad esempio, un layout contenente alcuni elementi), QtQuick Controls fornisce API delegate più semplici da utilizzare:

Dovresti preferire l'utilizzo dei delegati Qt upstream ove possibile.

Oltre a questi delegati Qt, Kirigami fornisce i propri equivalenti, con la funzionalità aggiuntiva di sottotitoli e icone:

L'API che termina con "Delegate" può essere impostata come delegato diretto della vista, proprio come gli esempi precedenti che utilizzavano 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"
            }
        }
    }
}

È previsto che sia TitleSubtitle che IconTitleSubtitle vengano utilizzati per sovrascrivere il contentItem di un delegato Qt, ad esempio:

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: genitore
            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"
                }
            }
        }
    }
}

Un esempio pratico di utilizzo dei delegati Kirigami può essere visto nel file ListItemTest nel repository Kirigami.