Curso de Python com Tkinter para Criação de Interfaces
Exibição de Dados com Treeview
Aprenda sobre exibição de dados com treeview
Aula 3.1: Exibição de Dados com Treeview 📊
Bem-vindos à primeira aula do módulo de "Interatividade e Componentes Complexos"! Hoje, vamos mergulhar em um dos widgets mais poderosos e versáteis do Tkinter para exibir dados: o ttk.Treeview.
1. Introdução Clara 🚀
O ttk.Treeview é um widget do conjunto de widgets temáticos (Tk themed widgets - ttk) que permite exibir dados em formato tabular (linhas e colunas) ou hierárquico (como uma árvore de diretórios). É a escolha ideal quando você precisa apresentar listas de informações, tabelas com múltiplos campos ou estruturas de dados aninhadas de forma clara e organizada.
Imagine que você está construindo um aplicativo de gerenciamento de estoque, um explorador de arquivos ou um sistema de lista de tarefas. Em todos esses cenários, você precisará exibir múltiplas peças de informação para cada item (nome, preço, quantidade; nome do arquivo, tamanho, data de modificação; título da tarefa, prazo, status). O Treeview simplifica essa tarefa, oferecendo funcionalidades como:
- Colunas personalizáveis: Defina quantas colunas quiser e configure seus cabeçalhos, largura e alinhamento.
- Rolagem: Suporte nativo para barras de rolagem, essencial para grandes conjuntos de dados.
- Seleção de itens: Permite que o usuário selecione uma ou várias linhas.
- Hierarquia (opcional): Capacidade de exibir dados em uma estrutura de árvore.
- Ordenação (programática): Fácil de implementar ordenação de colunas.
Vamos começar a explorar como usar este widget incrível!
2. Explicação Detalhada com Exemplos 🧑🏫
Para usar o Treeview, precisamos importá-lo do módulo tkinter.ttk.
2.1. Criando um Treeview Básico
Primeiro, vamos criar uma janela e o widget Treeview.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Exemplo Treeview Básico")
# Cria o widget Treeview
# 'columns' define os identificadores internos das colunas (exceto a primeira, que é a coluna de árvore/identificador)
tree = ttk.Treeview(root, columns=("Nome", "Idade", "Cidade"), show="headings")
# 'show="headings"' significa que apenas os cabeçalhos das colunas serão visíveis,
# e não a coluna padrão que exibe a estrutura de árvore (útil para tabelas simples).
tree.pack(padx=10, pady=10)
root.mainloop()Neste exemplo, columns=("Nome", "Idade", "Cidade") define as colunas que nosso Treeview terá. O parâmetro show="headings" é importante: ele faz com que o Treeview se comporte como uma tabela, exibindo apenas os cabeçalhos das colunas que definimos. Se show não for especificado ou for show="tree headings", uma coluna extra para a estrutura de árvore será exibida.
2.2. Definindo Cabeçalhos e Propriedades das Colunas
Após criar o Treeview, precisamos configurar os cabeçalhos que serão exibidos e as propriedades de cada coluna, como largura e alinhamento.
tree.heading(coluna, text="Texto do Cabeçalho"): Define o texto visível para o cabeçalho de uma coluna.tree.column(coluna, width=largura, anchor="alinhamento"): Configura a largura e o alinhamento do texto dentro da coluna.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Treeview com Cabeçalhos e Colunas Configuradas")
tree = ttk.Treeview(root, columns=("Nome", "Idade", "Cidade"), show="headings")
# Configura os cabeçalhos das colunas
tree.heading("Nome", text="Nome Completo")
tree.heading("Idade", text="Idade")
tree.heading("Cidade", text="Cidade Natal")
# Configura as propriedades de cada coluna
tree.column("Nome", width=150, anchor="w") # 'w' para west (esquerda)
tree.column("Idade", width=70, anchor="center")
tree.column("Cidade", width=120, anchor="w")
tree.pack(padx=10, pady=10)
root.mainloop()2.3. Adicionando Dados ao Treeview
Para adicionar dados, usamos o método tree.insert(). Cada linha é um "item" no Treeview.
tree.insert(parent, index, iid=None, **kw):parent: O item pai. Para itens de nível superior (sem hierarquia), use''(string vazia).index: A posição onde o item será inserido (e.g.,tk.ENDpara o final,0para o início).iid(opcional): Um identificador único para o item. Se não fornecido, o Tkinter gera um.values: Uma tupla ou lista de valores que correspondem às colunas definidas.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Treeview com Dados")
tree = ttk.Treeview(root, columns=("Nome", "Idade", "Cidade"), show="headings")
tree.heading("Nome", text="Nome Completo")
tree.heading("Idade", text="Idade")
tree.heading("Cidade", text="Cidade Natal")
tree.column("Nome", width=150, anchor="w")
tree.column("Idade", width=70, anchor="center")
tree.column("Cidade", width=120, anchor="w")
# Adiciona dados
tree.insert("", tk.END, values=("Alice Silva", 30, "São Paulo"))
tree.insert("", tk.END, values=("Bruno Costa", 25, "Rio de Janeiro"))
tree.insert("", tk.END, values=("Carla Souza", 35, "Belo Horizonte"))
tree.insert("", tk.END, values=("Daniel Lima", 28, "Curitiba"))
tree.pack(padx=10, pady=10)
root.mainloop()2.4. Adicionando uma Barra de Rolagem (Scrollbar) 📜
Para lidar com muitos dados, é essencial adicionar uma barra de rolagem ao Treeview. Isso é feito criando um ttk.Scrollbar e associando-o ao Treeview.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Treeview com Scrollbar")
# Frame para agrupar Treeview e Scrollbar
frame = ttk.Frame(root)
frame.pack(padx=10, pady=10, fill="both", expand=True)
tree = ttk.Treeview(frame, columns=("Nome", "Idade", "Cidade"), show="headings")
# Configuração de cabeçalhos e colunas (como nos exemplos anteriores)
tree.heading("Nome", text="Nome Completo")
tree.heading("Idade", text="Idade")
tree.heading("Cidade", text="Cidade Natal")
tree.column("Nome", width=150, anchor="w")
tree.column("Idade", width=70, anchor="center")
tree.column("Cidade", width=120, anchor="w")
# Adiciona dados (mais dados para que a barra de rolagem seja visível)
data = [
("Alice Silva", 30, "São Paulo"),
("Bruno Costa", 25, "Rio de Janeiro"),
("Carla Souza", 35, "Belo Horizonte"),
("Daniel Lima", 28, "Curitiba"),
("Eva Martins", 22, "Porto Alegre"),
("Felipe Gomes", 40, "Salvador"),
("Gabriela Santos", 29, "Fortaleza"),
("Hugo Oliveira", 33, "Recife"),
("Isabela Pereira", 27, "Manaus"),
("João Rodrigues", 45, "Brasília"),
("Kelly Fernandes", 31, "Goiânia"),
("Luiz Almeida", 26, "Florianópolis"),
("Mariana Carvalho", 38, "Vitória"),
("Nuno Barbosa", 32, "Natal"),
("Olívia Rocha", 24, "João Pessoa"),
("Pedro Dias", 36, "Campo Grande"),
]
for item in data:
tree.insert("", tk.END, values=item)
# Cria a barra de rolagem
scrollbar = ttk.Scrollbar(frame, orient="vertical", command=tree.yview)
tree.configure(yscrollcommand=scrollbar.set)
# Posiciona os widgets no frame
tree.grid(row=0, column=0, sticky="nsew")
scrollbar.grid(row=0, column=1, sticky="ns")
# Configura o redimensionamento do frame
frame.grid_rowconfigure(0, weight=1)
frame.grid_columnconfigure(0, weight=1)
root.mainloop()2.5. Manipulando Seleção de Itens
Podemos detectar quando um item é selecionado no Treeview usando o método bind(). O evento <<TreeviewSelect>> é disparado quando a seleção muda.
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
def item_selecionado(event):
for selected_item in tree.selection():
item_values = tree.item(selected_item, "values")
messagebox.showinfo("Item Selecionado", f"Você selecionou: {item_values}")
# Para pegar o ID do item:
# print(f"ID do item selecionado: {selected_item}")
root = tk.Tk()
root.title("Treeview com Seleção")
frame = ttk.Frame(root)
frame.pack(padx=10, pady=10, fill="both", expand=True)
tree = ttk.Treeview(frame, columns=("Nome", "Idade", "Cidade"), show="headings")
tree.heading("Nome", text="Nome Completo")
tree.heading("Idade", text="Idade")
tree.heading("Cidade", text="Cidade Natal")
tree.column("Nome", width=150, anchor="w")
tree.column("Idade", width=70, anchor="center")
tree.column("Cidade", width=120, anchor="w")
data = [
("Alice Silva", 30, "São Paulo"),
("Bruno Costa", 25, "Rio de Janeiro"),
("Carla Souza", 35, "Belo Horizonte"),
]
for item in data:
tree.insert("", tk.END, values=item)
# Vincula a função item_selecionado ao evento de seleção
tree.bind("<<TreeviewSelect>>", item_selecionado)
tree.grid(row=0, column=0, sticky="nsew")
frame.grid_rowconfigure(0, weight=1)
frame.grid_columnconfigure(0, weight=1)
root.mainloop()3. Código de Exemplo Oficial (Adaptado e Completo) 💻
Como a documentação oficial do Tkinter para ttk.Treeview é bastante técnica e focada nas opções de Tcl/Tk, apresento um exemplo Python completo e bem documentado que segue as boas práticas e incorpora os principais elementos que vimos, incluindo a barra de rolagem e a manipulação de seleção.
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
class AppTreeview(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.master.title("Gerenciador de Pessoas com Treeview")
self.master.geometry("550x400") # Define um tamanho inicial para a janela
self.pack(fill="both", expand=True, padx=10, pady=10)
self.create_widgets()
# Dados de exemplo
self.pessoas = [
("João Silva", 30, "Engenheiro", "São Paulo"),
("Maria Oliveira", 25, "Designer", "Rio de Janeiro"),
("Pedro Souza", 35, "Médico", "Belo Horizonte"),
("Ana Costa", 28, "Professor", "Curitiba"),
("Carlos Mendes", 42, "Desenvolvedor", "Porto Alegre"),
("Sofia Lima", 22, "Estudante", "Salvador"),
("Lucas Pereira", 38, "Gerente", "Fortaleza"),
("Isabela Rocha", 31, "Advogada", "Recife"),
("Gabriel Almeida", 29, "Analista", "Manaus"),
("Laura Santos", 45, "Contador", "Brasília"),
("Rafael Martins", 33, "Jornalista", "Goiânia"),
("Camila Fernandes", 27, "Marketing", "Florianópolis"),
("Daniel Carvalho", 50, "Arquiteto", "Vitória"),
("Beatriz Gomes", 23, "Programador", "Natal"),
("Fernando Dias", 40, "Empresário", "João Pessoa"),
]
self.carregar_dados()
def create_widgets(self):
# Frame para os controles de entrada e botões
control_frame = ttk.LabelFrame(self, text="Adicionar Nova Pessoa")
control_frame.pack(pady=10, padx=5, fill="x")
# Labels e Entradas
ttk.Label(control_frame, text="Nome:").grid(row=0, column=0, padx=5, pady=2, sticky="w")
self.nome_entry = ttk.Entry(control_frame, width=20)
self.nome_entry.grid(row=0, column=1, padx=5, pady=2, sticky="ew")
ttk.Label(control_frame, text="Idade:").grid(row=0, column=2, padx=5, pady=2, sticky="w")
self.idade_entry = ttk.Entry(control_frame, width=10)
self.idade_entry.grid(row=0, column=3, padx=5, pady=2, sticky="ew")
ttk.Label(control_frame, text="Profissão:").grid(row=1, column=0, padx=5, pady=2, sticky="w")
self.profissao_entry = ttk.Entry(control_frame, width=20)
self.profissao_entry.grid(row=1, column=1, padx=5, pady=2, sticky="ew")
ttk.Label(control_frame, text="Cidade:").grid(row=1, column=2, padx=5, pady=2, sticky="w")
self.cidade_entry = ttk.Entry(control_frame, width=10)
self.cidade_entry.grid(row=1, column=3, padx=5, pady=2, sticky="ew")
# Botões
add_button = ttk.Button(control_frame, text="Adicionar", command=self.adicionar_pessoa)
add_button.grid(row=2, column=0, columnspan=2, pady=5, sticky="ew")
delete_button = ttk.Button(control_frame, text="Excluir Selecionado", command=self.excluir_pessoa)
delete_button.grid(row=2, column=2, columnspan=2, pady=5, sticky="ew")
# Configura o redimensionamento das colunas no control_frame
control_frame.grid_columnconfigure(1, weight=1)
control_frame.grid_columnconfigure(3, weight=1)
# Frame para o Treeview e Scrollbar
tree_frame = ttk.Frame(self)
tree_frame.pack(fill="both", expand=True, padx=5, pady=5)
# Cria o Treeview
# 'columns' define os identificadores internos das colunas
# 'show="headings"' exibe apenas os cabeçalhos, sem a coluna de árvore padrão
self.tree = ttk.Treeview(tree_frame, columns=("Nome", "Idade", "Profissao", "Cidade"), show="headings")
# Configura os cabeçalhos das colunas
self.tree.heading("Nome", text="Nome Completo", anchor="w", command=lambda: self.ordenar_coluna("Nome", False))
self.tree.heading("Idade", text="Idade", anchor="center", command=lambda: self.ordenar_coluna("Idade", False))
self.tree.heading("Profissao", text="Profissão", anchor="w", command=lambda: self.ordenar_coluna("Profissao", False))
self.tree.heading("Cidade", text="Cidade", anchor="w", command=lambda: self.ordenar_coluna("Cidade", False))
# Configura as propriedades de cada coluna (largura, alinhamento)
self.tree.column("Nome", width=120, anchor="w")
self.tree.column("Idade", width=50, anchor="center")
self.tree.column("Profissao", width=100, anchor="w")
self.tree.column("Cidade", width=100, anchor="w")
# Cria a barra de rolagem vertical
vsb = ttk.Scrollbar(tree_frame, orient="vertical", command=self.tree.yview)
self.tree.configure(yscrollcommand=vsb.set)
# Cria a barra de rolagem horizontal (opcional, mas bom para tabelas largas)
hsb = ttk.Scrollbar(tree_frame, orient="horizontal", command=self.tree.xview)
self.tree.configure(xscrollcommand=hsb.set)
# Posiciona o Treeview e as Scrollbars usando grid
self.tree.grid(row=0, column=0, sticky="nsew")
vsb.grid(row=0, column=1, sticky="ns")
hsb.grid(row=1, column=0, sticky="ew")
# Configura o redimensionamento do tree_frame
tree_frame.grid_rowconfigure(0, weight=1)
tree_frame.grid_columnconfigure(0, weight=1)
# Vincula o evento de seleção de item para exibir detalhes ou permitir edição
self.tree.bind("<<TreeviewSelect>>", self.on_item_select)
def carregar_dados(self):
# Limpa o Treeview antes de carregar novos dados
for item in self.tree.get_children():
self.tree.delete(item)
# Insere os dados no Treeview
for pessoa in self.pessoas:
self.tree.insert("", tk.END, values=pessoa)
def adicionar_pessoa(self):
nome = self.nome_entry.get()
idade = self.idade_entry.get()
profissao = self.profissao_entry.get()
cidade = self.cidade_entry.get()
if nome and idade and profissao and cidade:
try:
idade_int = int(idade)
nova_pessoa = (nome, idade_int, profissao, cidade)
self.pessoas.append(nova_pessoa)
self.tree.insert("", tk.END, values=nova_pessoa)
# Limpa os campos de entrada
self.nome_entry.delete(0, tk.END)
self.idade_entry.delete(0, tk.END)
self.profissao_entry.delete(0, tk.END)
self.cidade_entry.delete(0, tk.END)
except ValueError:
messagebox.showerror("Erro", "A idade deve ser um número inteiro.")
else:
messagebox.showwarning("Atenção", "Por favor, preencha todos os campos.")
def excluir_pessoa(self):
selected_items = self.tree.selection()
if not selected_items:
messagebox.showwarning("Atenção", "Nenhum item selecionado para exclusão.")
return
if messagebox.askyesno("Confirmar Exclusão", "Tem certeza que deseja excluir o(s) item(ns) selecionado(s)?"):
for item_id in selected_items:
item_values = self.tree.item(item_id, "values")
# Remove do Treeview
self.tree.delete(item_id)
# Remove da lista de dados (importante para manter a consistência)
if item_values in self.pessoas:
self.pessoas.remove(item_values)
messagebox.showinfo("Sucesso", "Item(ns) excluído(s) com sucesso.")
def on_item_select(self, event):
selected_items = self.tree.selection()
if selected_items:
# Pega o primeiro item selecionado (pode ser ajustado para múltiplos)
item_id = selected_items[0]
item_values = self.tree.item(item_id, "values")
# Exibe os detalhes ou preenche campos para edição
print(f"Item selecionado: {item_values}")
# Exemplo: preencher os campos de entrada com os dados do item selecionado
self.nome_entry.delete(0, tk.END)
self.nome_entry.insert(0, item_values[0])
self.idade_entry.delete(0, tk.END)
self.idade_entry.insert(0, item_values[1])
self.profissao_entry.delete(0, tk.END)
self.profissao_entry.insert(0, item_values[2])
self.cidade_entry.delete(0, tk.END)
self.cidade_entry.insert(0, item_values[3])
def ordenar_coluna(self, col, reverse):
# Pega todos os dados da coluna especificada
l = [(self.tree.set(k, col), k) for k in self.tree.get_children('')]
# Converte para int se a coluna for 'Idade' para ordenar corretamente
if col == "Idade":
l.sort(key=lambda t: int(t[0]) if t[0].isdigit() else t[0], reverse=reverse)
else:
l.sort(key=lambda t: t[0], reverse=reverse)
# Reorganiza os itens no Treeview
for index, (val, k) in enumerate(l):
self.tree.move(k, '', index) # Move o item 'k' para a posição 'index' no pai '' (root)
# Inverte a ordem de ordenação para a próxima vez
self.tree.heading(col, command=lambda: self.ordenar_coluna(col, not reverse))
if __name__ == "__main__":
root = tk.Tk()
app = AppTreeview(master=root)
root.mainloop()Este código demonstra um aplicativo completo de gerenciamento de pessoas, onde você pode:
- Visualizar uma lista de pessoas em um
Treeview. - Adicionar novas pessoas através de campos de entrada.
- Excluir pessoas selecionadas.
- Clicar nos cabeçalhos das colunas para ordenar os dados.
- Clicar em uma linha para ver seus detalhes nos campos de entrada.
- O
Treeviewestá integrado com barras de rolagem vertical e horizontal.
4. Integração com Múltiplas Tecnologias (Não Aplicável) ❌
Nesta aula, estamos focando especificamente no ttk.Treeview do Tkinter. Não há "múltiplas tecnologias" no sentido de frameworks ou linguagens diferentes (como Express + Better-Auth). O Treeview já é uma parte integrada do Tkinter e ttk, e o exemplo acima mostra como ele se integra bem com outros widgets Tkinter (Entry, Button, Label, Scrollbar) para criar uma interface funcional.
5. Exercícios/Desafios 🏋️♀️
Agora é a sua vez de praticar! Use o código de exemplo como base e tente implementar as seguintes melhorias e funcionalidades:
Desafio 1: Adicionar e Remover Múltiplos Itens
- Modifique a função
adicionar_pessoapara que, ao invés de limpar os campos, ela permita adicionar várias pessoas rapidamente, talvez com um botão "Limpar Campos" separado. - Implemente uma forma de selecionar múltiplos itens no
Treeview(otree.selection()já retorna uma tupla de IDs selecionados, você só precisa iterar sobre eles). O botão "Excluir Selecionado" já lida com isso, mas certifique-se de entender como.
Desafio 2: Edição de Dados Existentes ✏️
- Ao selecionar um item no
Treeview, os dados devem ser carregados nos campos de entrada (já implementado no exemplo). - Adicione um botão "Atualizar Selecionado". Quando clicado, ele deve pegar os valores dos campos de entrada, encontrar o item selecionado no
Treeviewe atualizar seus valores. Lembre-se de atualizar tanto oTreeviewquanto a listaself.pessoas.- Dica: Use
tree.item(item_id, values=(novos_valores))para atualizar oTreeview.
- Dica: Use
Desafio 3: Filtragem de Dados 🔍
- Adicione um campo de entrada (Entry) e um botão "Filtrar" acima do
Treeview. - Quando o usuário digitar um texto e clicar em "Filtrar", o
Treeviewdeve exibir apenas as linhas onde o nome da pessoa contém o texto digitado.- Dica: Você precisará limpar o
Treeviewe reinserir apenas os itens que correspondem ao filtro.
- Dica: Você precisará limpar o
Desafio 4: Estilização Avançada (Opcional) ✨
- Explore as opções de estilo do
ttk.Treeviewusandottk.Style(). - Tente mudar a cor de fundo das linhas (alternando cores para linhas pares e ímpares), a cor do texto, ou a aparência dos cabeçalhos.
- Dica: Pesquise sobre
ttk.Style().configureettk.Style().mappara oTreeview.
- Dica: Pesquise sobre
6. Resumo e Próximos Passos 🔚
Nesta aula, você aprendeu a usar o poderoso widget ttk.Treeview para exibir dados tabulares e hierárquicos no Tkinter. Cobrimos:
- A criação de um
Treeviewe a definição de suas colunas. - A configuração de cabeçalhos e propriedades das colunas.
- A inserção de dados linha a linha.
- A integração essencial de barras de rolagem para lidar com grandes volumes de dados.
- A detecção e manipulação de eventos de seleção de itens.
- Um exemplo completo com funcionalidades de adição, exclusão e ordenação.
O Treeview é um componente fundamental para muitos tipos de aplicações. Dominá-lo abrirá muitas portas para a criação de interfaces ricas e funcionais.
Próximos Passos:
- Hierarquia de Dados: Explore como o
Treeviewpode ser usado para exibir dados em uma estrutura de árvore, usando o parâmetroparentde forma recursiva. - Integração com Bancos de Dados: Aprenda a carregar dados de um banco de dados (como SQLite) diretamente para o
Treeviewe a persistir alterações. - Edição In-line: Investigue como permitir que o usuário edite os dados diretamente nas células do
Treeview. - Drag-and-Drop: Descubra como implementar funcionalidades de arrastar e soltar itens dentro do
Treeviewou entreTreeviews.
Continue praticando com os desafios propostos e experimente criar suas próprias aplicações com este widget versátil! Boa sorte! 👍