Skip to main content
Ir para o conteúdo

Visualizações de lista

Uma visualização de lista pode ajudar você a exibir facilmente muitos componentes dinamicamente.

List views podem ajudar você a exibir objetos de um modelo de forma atraente. Para usar uma visualização de lista, você precisa manter o controle de três coisas:

  1. O modelo, que contém os dados que você deseja que sua visualização de lista exiba
  2. O delegado, que define como cada elemento no modelo será exibido
  3. A própria visualização de lista, que exibirá informações do modelo de acordo com o delegado

Caso você queira mais esclarecimentos, a documentação do Qt tem uma página informativa sobre o assunto.

Noções básicas de modelos e visualizações

Uma visualização de lista tem duas propriedades essenciais às quais devemos prestar atenção:

  • model, que aceita os dados ou o id do objeto que contém os dados
  • delegate, que aceita o componente que usaremos para exibir os dados no modelo

O modelo não é visível, pois contém apenas dados. Normalmente, o delegado será encapsulado em um componente para que seja reutilizável: ele serve como um modelo de como instanciar cada delegado.

Aqui está um exemplo que contém exatamente uma visualização de lista, um modelo e um delegado, usando um 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 exatamente o mesmo exemplo, em linha:

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

Compreendendo os modelos

O modelo contém os dados que serão usados ​​para preencher a visualização de lista. Diferentes maneiras de usar modelos têm diferentes maneiras de acessar os dados:

MANEIRA DE USARCOMO ACESSARQUANDO USAR
Modelos Qt com mais de uma funçãomodel.index, model.someroleNa maioria dos casos
Modelos Qt com somente uma funçãomodel.index, model.somerole, model.modelDataNa maioria dos casos, para prototipagem
Modelo de matriz JavaScriptmodel.index, model.modelDataPara prototipagem
Modelo inteiromodel.index, model.modelDataPara prototipagem

Você pode ler sobre outras maneiras de usar modelos na documentação do Qt.

Na tabela acima, "modelos Qt" refere-se tanto a modelos específicos de C++, como QAbstractListModel, quanto a modelos específicos de QML, como ListModel. Esta página do tutorial se concentrará apenas em modelos específicos de QML. Mais adiante, forneceremos um tutorial para Conectar modelos C++ a QML usando QAbstractListModel.

A propriedade model.index é disponibilizada para cada modelo e contém o índice (a posição) de cada delegado. Ela pode ser abreviada para index por conveniência.

A propriedade model.somerole mencionada acima é apenas um espaço reservado, não é uma propriedade específica que vem do QML: somerole pode ser qualquer função definida pelo modelo. No primeiro exemplo de código desta página, mostrado acima da tabela, o modelo plasmaProductsModel possui as funções product e target, que podem ser acessadas com model.product e model.target, respectivamente.

Assim como model.index pode ser abreviado para index, cada propriedade model.somerole pode ser abreviada para apenas somerole (como product) por conveniência, mas é recomendado que sejam transformadas em propriedades obrigatórias:

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

Além disso, se o modelo contiver apenas uma função ou não tiver nenhuma função, seus dados também poderão ser acessados ​​com a propriedade model.modelData, que também pode ser abreviada para modelData (e, como tal, também precisaria ser uma propriedade obrigatória):

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 // Isto corresponde à model.software
            }
        }
    }
}

Para comparação, veja como o código acima ficaria com uma matriz JavaScript, sem função:

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

Usar um número inteiro para o modelo pode ser útil para casos muito específicos, como prototipagem e testes:

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

Compreendendo visões e delegados

Vamos voltar ao exemplo 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`
            }
        }
    }
}

Ao contrário do modelo (que contém apenas dados) e de um delegado Componente (que só aparece quando instanciado), a visão é um componente visual imediatamente instanciado e, portanto, precisa ter suas dimensões definidas ou usar âncoras ou Layouts.

Como as visões são comumente listas de conteúdo que o usuário deseja percorrer, quando são adicionadas a uma Kirigami.ScrollablePage, as visões se tornam o conteúdo principal com pouco espaço ao redor delas, e não há necessidade de fazê-las preencher a página. Quando a visão é adicionada a uma Kirigami.Page simples, será necessário definir suas dimensões corretamente antes de ser exibida. Em outras palavras: na página rolável acima, anchors.fill: parent não é necessário; se uma página simples fosse usada, seria necessário.

Existem diversas APIs de visão que podem ser utilizadas, algumas do Qt e outras do Kirigami. Aqui estão as mais comumente utilizadas:

O delegado, por outro lado, sempre precisa ter suas dimensões definidas. Geralmente, suas dimensões são definidas para usar apenas a largura total da visão.

O uso mais comum de um delegado é dentro de um Componente, que não instancia o delegado imediatamente. Quando uma visão é construída, o delegado é então usado como um modelo para criar cada item na visão.

Embora você possa criar seus próprios componentes personalizados para serem usados ​​como delegados sem APIs Qt específicas para delegados (por exemplo, um Layout contendo alguns Itens), o QtQuick Controls fornece APIs de delegados que são mais simples de usar:

Você deve preferir usar os delegados Qt upstream sempre que possível.

Além desses delegados do Qt, o Kirigami fornece seus próprios equivalentes, com a funcionalidade adicional de legendas e ícones:

A API que termina com "Delegate" pode ser definida como um delegado direto da visão, assim como os exemplos anteriores que usaram 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"
            }
        }
    }
}

Espera-se que TitleSubtitle e IconTitleSubtitle sejam usados ​​para substituir o contentItem de um delegado Qt, por exemplo:

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

Um exemplo prático do uso de delegados Kirigami pode ser visto no arquivo ListItemTest no Repositório Kirigami.