Explorando o Componente ListView em QML

Exemplos Práticos de ListView com QML

Este guia explora diversas implementações do componente ListView em QML, demonstrando como criar interfaces de usuário dinâmicas e interativas.

  1. Barra de Navegação Vertical Simples

Este exemplo cria uma barra de navegação vertical estática com itans de texto clicáveis.


import QtQuick 2.15
import QtQuick.Controls 2.15

Rectangle {
   width: 100
   height: parent.height
   color: "grey"

   ListView {
       id: navigationList
       width: 90
       height: parent.height
       x: 10
       y: 10
       spacing: 10
       clip: true

       model: ['Início', 'Dados de Vendas', 'Gestão de Estoque', 'Planejamento de Frete', 'Publicidade', 'Configurações', 'Permissões de Usuário']
       delegate: Rectangle {
           width: 80
           height: 30
           color: 'transparent' // Cor padrão, pode ser alterada em outras partes
           radius: 10

           Text {
               id: itemLabel
               anchors.centerIn: parent
               color: 'white'
               text: modelData
               font.pointSize: 10
               font.bold: true
               font.family: "Arial" // Fonte alternativa
           }

           MouseArea {
               anchors.fill: parent
               onClicked: {
                   navigationList.currentIndex = index
               }
           }
       }

       highlight: Rectangle {
           color: "transparent"
           border.width: 2
           border.color: 'white'
           radius: 10
       }

       highlightMoveDuration: 0
   }
}
   
  1. Barra de Navegação Horizontal

Este exemplo demonstra um menu de navegação horizontal com itens clicáveis e destaque visual.


import QtQuick 2.15
import QtQuick.Controls 2.15

Rectangle {
   width: parent.width
   height: 38
   color: 'black'

   ListView {
       id: horizontalNav
       x: 10
       anchors.verticalCenter: parent.verticalCenter
       width: parent.width
       height: 30
       model: ['Página Inicial', 'Ferramentas', 'Loja', 'Relatório de Desempenho', 'Anúncios', 'Estoque', 'Relatório Financeiro', 'Análise de Produtos', 'Ajustes']
       clip: true

       delegate: Rectangle {
           width: 60
           height: 30
           color: 'transparent'
           radius: 10

           Text {
               text: modelData
               color: "white"
               anchors.centerIn: parent
               font.bold: true
               font.pointSize: 8
               font.family: "Verdana"
           }

           MouseArea {
               anchors.fill: parent
               onClicked: {
                   horizontalNav.currentIndex = index
               }
           }
       }
       spacing: 10
       highlight: Rectangle {
           color: "transparent"
           border.width: 3
           border.color: "yellow"
           radius: 10
       }
       highlightMoveDuration: 0
       orientation: ListView.Horizontal
   }
}
   
  1. Exibindo Dados Estruturados com ListModel

Este exemplo utiliza um ListModel para gerenciar dados com múltiplos papéis (roles) e exibi-los em um ListView, com destaque para o item selecionado.


import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.3

Rectangle {
   width: 360
   height: 300
   color: "#EEEEEE"

   Component {
       id: productDelegate
       Item {
           id: itemWrapper
           width: parent.width
           height: 30

           MouseArea {
               anchors.fill: parent
               onClicked: itemWrapper.ListView.view.currentIndex = index
           }

           RowLayout {
               anchors.left: parent.left
               anchors.verticalCenter: parent.verticalCenter
               spacing: 8

               Text {
                   id: nameText
                   text: name
                   color: itemWrapper.ListView.isCurrentItem ? "red" : "black"
                   font.pixelSize: itemWrapper.ListView.isCurrentItem ? 22 : 18
                   Layout.preferredWidth: 120
               }

               Text {
                   text: price
                   color: itemWrapper.ListView.isCurrentItem ? "red" : "black"
                   font.pixelSize: itemWrapper.ListView.isCurrentItem ? 22 : 18
                   Layout.preferredWidth: 80
               }

               Text {
                   text: manufacturer
                   color: itemWrapper.ListView.isCurrentItem ? "red" : "black"
                   font.pixelSize: itemWrapper.ListView.isCurrentItem ? 22 : 18
                   Layout.fillWidth: true
               }
           }
       }
   }

   ListView {
       id: productListView
       anchors.fill: parent
       delegate: productDelegate

       model: ListModel {
           id: productModel
           ListElement { name: "iPhone 3GS"; price: "1000"; manufacturer: "Apple" }
           ListElement { name: "iPhone 4"; price: "1800"; manufacturer: "Apple" }
           ListElement { name: "iPhone 4S"; price: "2300"; manufacturer: "Apple" }
           ListElement { name: "iPhone 5"; price: "4900"; manufacturer: "Apple" }
           ListElement { name: "B199"; price: "1590"; manufacturer: "HuaWei" }
           ListElement { name: "MI 2S"; price: "1999"; manufacturer: "XiaoMi" }
           ListElement { name: "GALAXY S5"; price: "4699"; manufacturer: "Samsung" }
       }

       focus: true
       highlight: Rectangle { color: "lightblue" }
   }
}
   
  1. ListView com Cabeçalho, Rodapé e Interação

Este exemplo expande o anterior, adicionando um cabeçalho, um rodapé dinâmico e a capacidade de interagir com os itens (seleção e exclusão por duplo clique).


import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.3

Rectangle {
   width: 360
   height: 300
   color: "#EEEEEE"

   Component {
       id: header
       Item {
           width: parent.width
           height: 30
           RowLayout {
               anchors.left: parent.left
               anchors.verticalCenter: parent.verticalCenter
               spacing: 8
               Text { text: "Nome"; font.bold: true; font.pixelSize: 20; Layout.preferredWidth: 120 }
               Text { text: "Preço"; font.bold: true; font.pixelSize: 20; Layout.preferredWidth: 120 }
               Text { text: "Fab."; font.bold: true; font.pixelSize: 20; Layout.preferredWidth: 120 }
           }
       }
   }

   Component {
       id: itemDelegate
       Item {
           id: itemWrapper
           width: parent.width
           height: 30

           MouseArea {
               anchors.fill: parent
               onClicked: {
                   itemWrapper.ListView.view.currentIndex = index
                   console.log("Índice selecionado:", index)
               }
               onDoubleClicked: {
                   itemWrapper.ListView.view.model.remove(index)
               }
           }

           RowLayout {
               anchors.left: parent.left
               anchors.verticalCenter: parent.verticalCenter
               spacing: 8
               Text { text: name; color: itemWrapper.ListView.isCurrentItem ? "red" : "black"; font.pixelSize: itemWrapper.ListView.isCurrentItem ? 22 : 18; Layout.preferredWidth: 120 }
               Text { text: price; color: itemWrapper.ListView.isCurrentItem ? "red" : "black"; font.pixelSize: itemWrapper.ListView.isCurrentItem ? 22 : 18; Layout.preferredWidth: 120 }
               Text { text: manufacturer; color: itemWrapper.ListView.isCurrentItem ? "red" : "black"; font.pixelSize: itemWrapper.ListView.isCurrentItem ? 22 : 18; Layout.preferredWidth: 120 }
           }
       }
   }

   Component {
       id: footer
       Text {
           width: parent.width
           font.italic: true
           font.bold: true
           font.pointSize: 8
           color: "blue"
           height: 30
           verticalAlignment: Text.AlignVCenter
       }
   }

   ListView {
       id: productListView
       anchors.fill: parent
       delegate: itemDelegate
       header: header
       footer: footer

       model: ListModel {
           id: productModel
           ListElement { name: "iPhone 3GS"; price: "1000"; manufacturer: "Apple" }
           ListElement { name: "iPhone 4"; price: "1800"; manufacturer: "Apple" }
           ListElement { name: "iPhone 4S"; price: "2300"; manufacturer: "Apple" }
           ListElement { name: "iPhone 5"; price: "4900"; manufacturer: "Apple" }
           ListElement { name: "B199"; price: "1590"; manufacturer: "HuaWei" }
           ListElement { name: "MI 2S"; price: "1999"; manufacturer: "XiaoMi" }
           ListElement { name: "GALAXY S5"; price: "4699"; manufacturer: "Samsung" }
       }

       focus: true
       highlight: Rectangle { color: "lightblue" }

       onCurrentIndexChanged: {
           if (currentIndex >= 0) {
               var data = model.get(currentIndex)
               footerItem.text = `${data.name}, ${data.price}, ${data.manufacturer}`
           } else {
               footerItem.text = ""
           }
       }
   }
}
   
  1. Gerenciamento de Dados (Adicionar, Remover, Limpar)

Este exemplo adiciona funcionalidades para adicionar novos itens, remover itens selecionados e limpar toda a lista, além de exibir informações no rodapé.


import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.3

Rectangle {
   width: 360
   height: 300
   color: "#EEEEEE"

   Component {
       id: headerView
       Item {
           width: parent.width
           height: 30
           RowLayout {
               anchors.left: parent.left
               anchors.verticalCenter: parent.verticalCenter
               spacing: 8
               Text { text: "Nome"; font.bold: true; font.pixelSize: 20; Layout.preferredWidth: 120 }
               Text { text: "Preço"; font.bold: true; font.pixelSize: 20; Layout.preferredWidth: 120 }
               Text { text: "Fab."; font.bold: true; font.pixelSize: 20; Layout.preferredWidth: 120 }
           }
       }
   }

   Component {
       id: itemDelegate
       Item {
           id: itemWrapper
           width: parent.width
           height: 30

           MouseArea {
               anchors.fill: parent
               onClicked: {
                   itemWrapper.ListView.view.currentIndex = index
                   mouse.accepted = true
               }
               onDoubleClicked: {
                   itemWrapper.ListView.view.model.remove(index)
                   mouse.accepted = true
               }
           }

           RowLayout {
               anchors.left: parent.left
               anchors.verticalCenter: parent.verticalCenter
               spacing: 8
               Text { text: name; color: itemWrapper.ListView.isCurrentItem ? "red" : "black"; font.pixelSize: itemWrapper.ListView.isCurrentItem ? 22 : 18; Layout.preferredWidth: 120 }
               Text { text: price; color: itemWrapper.ListView.isCurrentItem ? "red" : "black"; font.pixelSize: itemWrapper.ListView.isCurrentItem ? 22 : 18; Layout.preferredWidth: 120 }
               Text { text: manufacturer; color: itemWrapper.ListView.isCurrentItem ? "red" : "black"; font.pixelSize: itemWrapper.ListView.isCurrentItem ? 22 : 18; Layout.preferredWidth: 120 }
           }
       }
   }

   Component {
       id: footerView
       Item {
           id: footerRootItem
           width: parent.width
           height: 30
           property alias text: statusText.text
           signal clearAll()
           signal addItem()

           Button {
               id: clearButton
               anchors.right: parent.right
               anchors.verticalCenter: parent.verticalCenter
               text: "Limpar"
               onClicked: footerRootItem.clearAll()
           }

           Button {
               id: addButton
               anchors.right: clearButton.left
               anchors.rightMargin: 4
               anchors.verticalCenter: parent.verticalCenter
               text: "Adicionar"
               onClicked: footerRootItem.addItem()
           }

           Text {
               id: statusText
               anchors.left: parent.left
               anchors.verticalCenter: parent.verticalCenter
               font.italic: true
               font.bold: true
               font.pointSize: 8
               color: "blue"
               height: 30
           }
       }
   }

   ListView {
       id: productListView
       anchors.fill: parent
       delegate: itemDelegate
       header: headerView
       footer: footerView

       model: ListModel {
           id: productModel
           ListElement { name: "iPhone 3GS"; price: "1000"; manufacturer: "Apple" }
           ListElement { name: "iPhone 4"; price: "1800"; manufacturer: "Apple" }
           ListElement { name: "iPhone 4S"; price: "2300"; manufacturer: "Apple" }
           ListElement { name: "iPhone 5"; price: "4900"; manufacturer: "Apple" }
           ListElement { name: "B199"; price: "1590"; manufacturer: "HuaWei" }
           ListElement { name: "MI 2S"; price: "1999"; manufacturer: "XiaoMi" }
           ListElement { name: "GALAXY S5"; price: "4699"; manufacturer: "Samsung" }
       }

       focus: true
       highlight: Rectangle { color: "lightblue" }

       onCurrentIndexChanged: {
           if (currentIndex >= 0) {
               var data = model.get(currentIndex)
               footerItem.text = `${data.name}, ${data.price}, ${data.manufacturer}`
           } else {
               footerItem.text = ""
           }
       }

       function addNewItem() {
           model.append({
                            "name": "MX3",
                            "price": "1799",
                            "manufacturer": "MeiZu"
                        })
       }

       Component.onCompleted: {
           footerItem.clearAll.connect(model.clear)
           footerItem.addItem.connect(addNewItem)
       }
   }
}
   
  1. Animações e Movimentação de Itens (Subir/Descer)

Este exemplo final demonstra o uso de transições animadas para adição, remoção e movimentação de itens dentro do ListView, incluindo funcionalidades para mover itens para cima e para baixo na lista.


import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.3

Rectangle {
   width: 500
   height: 400
   color: "#EEEEEE"

   Component {
       id: headerView
       Item {
           width: parent.width
           height: 30
           RowLayout {
               anchors.left: parent.left
               anchors.verticalCenter: parent.verticalCenter
               spacing: 8
               Text { text: "Nome"; font.bold: true; font.pixelSize: 20; Layout.preferredWidth: 120 }
               Text { text: "Preço"; font.bold: true; font.pixelSize: 20; Layout.preferredWidth: 120 }
               Text { text: "Fab."; font.bold: true; font.pixelSize: 20; Layout.preferredWidth: 120 }
           }
       }
   }

   Component {
       id: itemDelegate
       Item {
           id: itemWrapper
           width: parent.width
           height: 30

           MouseArea {
               anchors.fill: parent
               onClicked: {
                   itemWrapper.ListView.view.currentIndex = index
                   mouse.accepted = true
               }
               onDoubleClicked: {
                   itemWrapper.ListView.view.model.remove(index)
                   mouse.accepted = true
               }
           }

           RowLayout {
               anchors.left: parent.left
               anchors.verticalCenter: parent.verticalCenter
               spacing: 8
               Text { text: name; color: itemWrapper.ListView.isCurrentItem ? "red" : "black"; font.pixelSize: itemWrapper.ListView.isCurrentItem ? 22 : 18; Layout.preferredWidth: 120 }
               Text { text: price; color: itemWrapper.ListView.isCurrentItem ? "red" : "black"; font.pixelSize: itemWrapper.ListView.isCurrentItem ? 22 : 18; Layout.preferredWidth: 120 }
               Text { text: manufacturer; color: itemWrapper.ListView.isCurrentItem ? "red" : "black"; font.pixelSize: itemWrapper.ListView.isCurrentItem ? 22 : 18; Layout.preferredWidth: 120 }
           }
       }
   }

   Component {
       id: footerView
       Item {
           id: footerRootItem
           width: parent.width
           height: 30
           property alias text: statusText.text
           signal clearAll()
           signal addItem()
           signal insertItem()
           signal moveItemUp()
           signal moveItemDown()

           Button { id: clearButton; anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; text: "Limpar"; onClicked: footerRootItem.clearAll() }
           Button { id: addButton; anchors.right: clearButton.left; anchors.rightMargin: 4; anchors.verticalCenter: parent.verticalCenter; text: "Adicionar"; onClicked: footerRootItem.addItem() }
           Button { id: insertButton; anchors.right: addButton.left; anchors.rightMargin: 4; anchors.verticalCenter: parent.verticalCenter; text: "Inserir"; onClicked: footerRootItem.insertItem() }
           Button { id: moveDownButton; anchors.right: insertButton.left; anchors.rightMargin: 4; anchors.verticalCenter: parent.verticalCenter; text: "Baixo"; onClicked: footerRootItem.moveItemDown() }
           Button { id: moveUpButton; anchors.right: moveDownButton.left; anchors.rightMargin: 4; anchors.verticalCenter: parent.verticalCenter; text: "Cima"; onClicked: footerRootItem.moveItemUp() }

           Text {
               id: statusText
               anchors.left: parent.left
               anchors.top: moveUpButton.bottom // Posiciona abaixo dos botões
               font.italic: true
               font.bold: true
               font.pointSize: 8
               color: "blue"
               height: 30
               verticalAlignment: Text.AlignVCenter
           }
       }
   }

   ListView {
       id: productListView
       anchors.fill: parent
       delegate: itemDelegate
       header: headerView
       footer: footerView
       focus: true
       highlight: Rectangle { color: "lightblue" }

       model: ListModel {
           id: productModel
           ListElement { name: "iPhone 3GS"; price: "1000"; manufacturer: "Apple" }
           ListElement { name: "iPhone 4"; price: "1800"; manufacturer: "Apple" }
           ListElement { name: "iPhone 4S"; price: "2300"; manufacturer: "Apple" }
           ListElement { name: "iPhone 5"; price: "4900"; manufacturer: "Apple" }
           ListElement { name: "B199"; price: "1590"; manufacturer: "HuaWei" }
           ListElement { name: "MI 2S"; price: "1999"; manufacturer: "XiaoMi" }
           ListElement { name: "GALAXY S5"; price: "4699"; manufacturer: "Samsung" }
       }

       onCurrentIndexChanged: {
           if (currentIndex >= 0) {
               var data = model.get(currentIndex)
               footerItem.text = `${data.name}, ${data.price}, ${data.manufacturer}`
           } else {
               footerItem.text = ""
           }
       }

       populate: Transition { NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 1000 } }
       add: Transition { ParallelAnimation { NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 1000 }; NumberAnimation { properties: "x,y"; from: 0; duration: 1000 } } }
       displaced: Transition { SpringAnimation { property: "y"; spring: 3; damping: 0.1; epsilon: 0.25 } }
       remove: Transition { SequentialAnimation { NumberAnimation { property: "y"; to: 0; duration: 600 }; NumberAnimation { property: "opacity"; to: 0; duration: 400 } } }
       move: Transition { NumberAnimation { property: "y"; duration: 700; easing.type: Easing.InQuart } }

       function addOne() {
           model.append({ "name": "MX3", "price": "1799", "manufacturer": "MeiZu" })
       }

       function insertOne() {
           var insertIndex = currentIndex < 0 ? 0 : currentIndex + 1
           model.insert(insertIndex, { "name": "HTC One E8", "price": "2999", "manufacturer": "HTC" })
       }

       function moveUp() {
           if (currentIndex > 0) {
               model.move(currentIndex, currentIndex - 1, 1)
           }
       }

       function moveDown() {
           if (currentIndex !== -1 && currentIndex < model.count - 1) {
               model.move(currentIndex, currentIndex + 1, 1)
           }
       }

       Component.onCompleted: {
           footerItem.clearAll.connect(model.clear)
           footerItem.addItem.connect(addOne)
           footerItem.insertItem.connect(insertOne)
           footerItem.moveItemUp.connect(moveUp)
           footerItem.moveItemDown.connect(moveDown)
       }
       ScrollBar.vertical: ScrollBar {}
   }
}
   

Tags: qml listview Model Delegate ListModel

Publicado em 7-21 15:11