Bibliotecas Gráficas

Modulo TKinter

O módulo tkinter é a biblioteca padrão do Python para criar interfaces gráficas (GUI). Ele é um wrapper para a biblioteca Tk, que fornece elementos visuais como botões, rótulos, caixas de entrada e janelas.

O Packer (pack) é um gerenciador de layout do tkinter que organiza widgets automaticamente dentro de uma janela. Ele posiciona os elementos em relação ao espaço disponível e ao que já foi adicionado.

pack() vs grid() vs place()
  • pack() → Simples e empilha widgets automaticamente.
  • grid() → Usa uma grade (linhas e colunas) para organizar widgets.
  • place() → Posiciona os widgets de forma exata (coordenadas x, y).

Não é possivel misturar grid e pack no mesmo layout. 

tkinter.py
import tkinter

# Define uma tupla da fonte, tamanho e estilo da fonte
FONT = ("Arial", 24, "bold")

windows = tkinter.Tk()
windows.title("My GUI Test")
windows.minsize(width=500, height=300)
windows.config(padx=20, pady=20) # Padding das bordas da tela

# Cria um label
my_label = tkinter.Label(text="Hello, World!", font=FONT)
# Adiciona o label na janela com o packer
my_label.pack(side="right")  # expand=true, ocupa todo espaço da tela

# Depois de criado posso configurar as propriedades pelo metodo config() ou pelo indice
my_label.config(text="Nova Janela")
my_label["background"] = "red"


def button_clicked():
    # get() metodo que retorna a entrada em string
    my_label["text"] = input.get()


# command recebe o nome de uma função de eventos
button = tkinter.Button(text="Click Here", command=button_clicked)
button.place(x=200, y=0)
# button.grid(column=0, row=0) # Só pode ser usado sozinho

input = tkinter.Entry(width=10)
input.place(x=0, y=0)  # coordenadas exatas

# Metodo para manter a janela aberta e rodando
windows.mainloop()

Vários exemplos da classe tkinter

tkinter_widget_demo.py
from tkinter import *

#Creating a new window and configurations
window = Tk()
window.title("Widget Examples")
window.minsize(width=500, height=500)

#Labels
label = Label(text="This is old text")
label.config(text="This is new text")
label.pack()

#Buttons
def action():
    print("Do something")

#calls action() when pressed
button = Button(text="Click Me", command=action)
button.pack()

#Entries
entry = Entry(width=30)
#Add some text to begin with
entry.insert(END, string="Some text to begin with.")
#Gets text in entry
print(entry.get())
entry.pack()

#Text
text = Text(height=5, width=30)
#Puts cursor in textbox.
text.focus()
#Adds some text to begin with.
text.insert(END, "Example of multi-line text entry.")
#Get's current value in textbox at line 1, character 0
print(text.get("1.0", END))
text.pack()

#Spinbox
def spinbox_used():
    #gets the current value in spinbox.
    print(spinbox.get())
spinbox = Spinbox(from_=0, to=10, width=5, command=spinbox_used)
spinbox.pack()

#Scale
#Called with current scale value.
def scale_used(value):
    print(value)
scale = Scale(from_=0, to=100, command=scale_used)
scale.pack()

#Checkbutton
def checkbutton_used():
    #Prints 1 if On button checked, otherwise 0.
    print(checked_state.get())
#variable to hold on to checked state, 0 is off, 1 is on.
checked_state = IntVar()
checkbutton = Checkbutton(text="Is On?", variable=checked_state, command=checkbutton_used)
checked_state.get()
checkbutton.pack()

#Radiobutton
def radio_used():
    print(radio_state.get())
#Variable to hold on to which radio button value is checked.
radio_state = IntVar()
radiobutton1 = Radiobutton(text="Option1", value=1, variable=radio_state, command=radio_used)
radiobutton2 = Radiobutton(text="Option2", value=2, variable=radio_state, command=radio_used)
radiobutton1.pack()
radiobutton2.pack()


#Listbox
def listbox_used(event):
    # Gets current selection from listbox
    print(listbox.get(listbox.curselection()))

listbox = Listbox(height=4)
fruits = ["Apple", "Pear", "Orange", "Banana"]
for item in fruits:
    listbox.insert(fruits.index(item), item)
listbox.bind("<<ListboxSelect>>", listbox_used)
listbox.pack()
window.mainloop()
gerador_senhas_tk.py
from tkinter import *
from tkinter import messagebox
from random import shuffle, randint, choice
import json

# ------ GENERATOR PASS ------- #


def generate_password():

    letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
               'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
    numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
    symbols = ['!', '#', '$', '%', '&', '(', ')', '*', '+']

    password_letters = [choice(letters) for _ in range(randint(8, 10))]
    password_symbols = [choice(symbols) for _ in range(randint(2, 4))]
    password_numbers = [choice(numbers)for _ in range(randint(2, 4))]

    password_list = password_letters + password_symbols + password_numbers
    shuffle(password_list)

    # junta todos os elementos da lista e retorna uma string
    password = ''.join(password_list)
    # Sempre limpo o campo antes de gerar uma nova senha
    password_entry.delete(0, END)
    password_entry.insert(0, password)


# ------ SAVE PASS ----- #
def save():

    website = website_entry.get()
    email = email_entry.get()
    password = password_entry.get()
    new_data = {
        website: {
            "email": email,
            "password": password
        }
    }

    if website == "" or email == "" or password == "":
        messagebox.showerror("Error", "Please fill out all fields")
        return
    else:
        try:
            with open('data.json', 'r') as data_file:
                data = json.load(data_file)
        except FileNotFoundError:
            with open('data.json', 'w') as data_file:
                json.dump(new_data, data_file, indent=4)
        else:
            data.update(new_data)
            with open('data.json', 'w') as data_file:
                json.dump(data, data_file, indent=4)
        finally:
            website_entry.delete(0, END)
            password_entry.delete(0, END)

# ------ FIND PASSWORD ------- #


def find_password():
    website = website_entry.get()
    try:
        with open('data.json', 'r') as data_file:
            data = json.load(data_file)
    except FileNotFoundError:
        messagebox.showerror("Error", "Arquivo de dados não encontrado")
    else:
        if website in data:
            email = data[website]["email"]
            password = data[website]["password"]
            messagebox.showinfo(
                title=website, message=f"Email: {email}\nPassword: {password}")
        else:
            messagebox.showinfo(
                "Error", f"Nehuma senha cadastrada no site {website}")


# ------ UI SETUP ------- #
window = Tk()
window.title("Gerenciador de Senhas")
window.config(padx=50, pady=50)

canvas = Canvas(height=200, width=200)
logo_image = PhotoImage(file="logo.png")
canvas.create_image(100, 100, image=logo_image)
canvas.grid(row=0, column=1)

# Labels
website_label = Label(text="Website:")
website_label.grid(row=1, column=0)
email_label = Label(text="Email/Username:")
email_label.grid(row=2, column=0)
password_label = Label(text="Password:")
password_label.grid(row=3, column=0)

# Entrys
website_entry = Entry(width=23)
website_entry.grid(row=1, column=1)
website_entry.focus()
email_entry = Entry(width=35)
email_entry.grid(row=2, column=1, columnspan=2)
# insere um email no inicio, se fosse a constante END seria no fim dos caracteres
email_entry.insert(0, "example@email.com")
password_entry = Entry(width=23)
password_entry.grid(row=3, column=1)

# Buttons
search_button = Button(text="Pesquisar", width=10, command=find_password)
search_button.grid(row=1, column=2)

generate_password_button = Button(
    text="Gerar Senha", command=generate_password)
generate_password_button.grid(row=3, column=2)

add_button = Button(text="Add", width=36, command=save)
add_button.grid(row=4, column=1, columnspan=2)

window.mainloop()

Projeto Gerador de senhas, para exemplo de algumas funções do tkinter.


streamlit

Streamlit é uma biblioteca de código aberto para desenvolver aplicações web interativas de forma simples e rápida, especialmente voltada para data science, machine learning e análise de dados.

A principal característica do Streamlit é sua facilidade de uso. Em poucas linhas de código, você pode transformar um script Python comum em uma aplicação web interativa e visual, sem a necessidade de entender HTML, CSS ou JavaScript.

O Streamlit funciona como uma aplicação baseada em reatividade, onde a interface do usuário (UI) é recalculada automaticamente sempre que qualquer interação ocorre. Ou seja, cada vez que o usuário interage (clicando no botão, inserindo texto, etc.), o script Python é executado novamente do início ao fim. caso queira guardar alguma informação como variavel para não ser recarregada use a st.session_state que é um dicionário persistente que guarda valores entre interações no Streamlit.

Instalação e Execução streamlit

bash
$ pip install streamlit # instala a biblioteca
$ streamlit run form.py # Executa o arquivo no servidor http://localhost:8501/

| Exemplo aplicação de Filmes

Resultado abaixo

form.py
import streamlit as st
import conexao_db

st.title("Filmes")

nome = st.text_input("Nome do filme")
ano = st.number_input("Ano de lançamento", min_value=2010, 
                    max_value=2025)
nota = st.slider("Nota do filme", min_value=1.0, max_value=10.0)

if st.button("Adicionar"):
    conexao_db.inserir_filme(nome, ano, nota)
    st.success("Filme adicionado com sucesso")

filmes = conexao_db.listar_filmes()
st.header("Lista de Filmes")
st.table(filmes)
conexao_db.py
import sqlite3

def connection():
    connection = sqlite3.connect('filmes.db')
    cursor = connection.cursor()
    cursor.execute(
    """
    CREATE TABLE IF NOT EXISTS filmes(
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            nome VARCHAR(255) NOT NULL,
            ano INTEGER NOT NULL,
            nota REAL NOT NULL
        );
    """
    )
    return connection

def inserir_filme(nome, ano, nota):
    conn = connection()
    cursor = conn.cursor()
    cursor.execute('INSERT INTO filmes (nome, ano, nota) VALUES (?, ?, ?)',(nome,ano,nota))
    conn.commit()
    conn.close()

def listar_filmes():
    conn = connection()
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM filmes')
    filmes = cursor.fetchall()
    conn.close()
    return filmes
sessao_streamlit.py
import streamlit as st

# Inicializa o contador
if "contador" not in st.session_state:
    st.session_state.contador = 0

# Botão para incrementar
if st.button("Clique para contar"):
    st.session_state.contador += 1

# Mostra o valor atual
st.write(f"Contador: {st.session_state.contador}")

  • O contador não é resetado ao clicar no botão.

  • Ele se mantém enquanto a sessão estiver ativa no navegador.

Assuntos Relacionados


Gradio

Gradio é uma biblioteca em Python que permite criar interfaces gráficas interativas para modelos de machine learning, APIs ou qualquer outro código Python de forma simples e rápida. Ele é muito usado para criar demonstrações de modelos de IA sem precisar desenvolver um front-end complexo. Documentação pode ser encontrada AQUI. Biblioteca externa precisa ser instalada.

gradio.py
import gradio as gr

def somar(n1, n2):
    return n1+n2, "Parabéns pela soma"

iface = gr.Interface(
    fn=somar,
    inputs=["number","number"], # number é um tipo de entrada numerica
    outputs=["number","text"], # como a função tem dois retornos coloco na ordem
    title="Calculadora",
    description="Soma de dois números",
)

iface.launch()

matplotlib

A matplotlib é uma das bibliotecas externas (necessário instalar com pip) mais populares do Python para visualização de dados — especialmente gráficos 2D.

É uma biblioteca poderosa e flexível para criar gráficos e visualizações. Ela te permite gerar diversos tipos de graficos.

📈 Tipos comuns de gráficos:
Tipo Função
Linha plt.plot()
Barras plt.bar() ou plt.barh()
Pizza plt.pie()
Dispersão plt.scatter()
Histograma plt.hist()
Boxplot plt.boxplot()

 

matplotlib.py
import matplotlib.pyplot as plt

# Dados
x = [1, 2, 3, 4, 5]
y = [10, 20, 25, 30, 40]

# Criar gráfico
plt.plot(x, y)

# Títulos e rótulos
plt.title('Crescimento de vendas')
plt.xlabel('Mês')
plt.ylabel('Vendas')

# Mostrar
plt.show()

 Ela tem uma interface chamada pyplot (importada como plt), que é inspirada no estilo do MATLAB — bem direta e procedural.

pyplot.py
plt.plot(x, y, color='green', linestyle='--', marker='o', label='vendas')
plt.legend() 
plt.savefig("grafico.png") # Salvar como imagem

Flet

O Flet é um framework (baseado no flutter) para criar interfaces gráficas de usuário (GUI) modernas e responsivas usando apenas Python, sem precisar mexer diretamente com HTML, CSS ou JavaScript. O Flet tem o hot reload (recarrega automaticamente quaisquer alterações salvas).

Tabela com as principais propriedades do page no Flet:
Propriedade Tipo / Enum O que faz
title str Define o título da janela/navegador.
bgcolor str ou ft.colors Define a cor de fundo da página.
horizontal_alignment ft.CrossAxisAlignment Alinha os elementos horizontalmente (esquerda, centro, direita, etc).
vertical_alignment ft.MainAxisAlignment Alinha os elementos verticalmente (topo, centro, base, etc).
theme_mode ft.ThemeMode.LIGHT / DARK / SYSTEM Define o tema claro/escuro da interface.
window_width float Define a largura da janela (em apps desktop).
window_height float Define a altura da janela.
window_resizable bool Permite ou não redimensionar a janela.
window_maximizable bool Permite ou não maximizar.
window_minimizable bool Permite ou não minimizar.
window_full_screen bool Abre a janela em tela cheia.
padding int / ft.Padding Define o espaçamento interno da página.
scroll ft.ScrollMode.AUTO / ALWAYS / NONE Define se a rolagem está habilitada.
fonts dict[str, str] Define fontes personalizadas.
theme ft.Theme Define o tema customizado da interface.
add(...) Método Adiciona elementos à página.
update() Método Atualiza a página após mudanças dinâmicas.
clean() Método Remove todos os elementos da página.

Comandos Flet

Se usar apenas o run, ele procura o arquivo main.py para executar.

Obs.: pode rodar o programa com python arquivo.py também.

bash
$ pip install flet # instala a biblioteca
$ flet run arquivo.py # roda em modo desktop
$ flet run arquivo.py --web # roda em modo web
flet.py
import flet as ft

# usando tipy hint aqui
def main(page:ft.Page):
    page.title = "Flet" # Título da página

    # tambem tem cores definidas do proprio flet, ft.colors.BLUE...
    page.bgcolor = "gray"

    # alinhar horizontalmente os elementos dentro da page — ou seja, no eixo principal horizontal# Adiciona padding a página, ou seja, espaço entre os elementos e as bordas da página. (da esquerda para a direita).
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER

    page.vertical_alignment = ft.MainAxisAlignment.CENTER # Alinhamento vertical

    # Adiciona padding a página, ou seja, espaço entre os elementos e as bordas da página.
    page.padding = ft.padding.all(100)

    texto_teste = ft.Text(
        value="Texto de teste",
        theme_style=ft.TextThemeStyle.DISPLAY_LARGE,
        bgcolor=ft.colors.WHITE30,
        max_lines=2, # Limita o número de linhas do texto a 2
        # Adiciona reticências se o texto for muito longo e não couber no limite de linhas definido acima
        overflow=ft.TextOverflow.ELLIPSIS,
        style=ft.TextStyle(
            color=ft.colors.RED_900,
            font_family="Arial",
        ),
        text_align=ft.TextAlign.CENTER, # Alinhamento do texto dentro do elemento
    )

    estilo_span1 = ft.TextStyle(
        color=ft.Colors.BLUE_900,
       decoration=ft.TextDecoration.UNDERLINE,
    )
    texto2_span = ft.Text(
        spans=[
            ft.TextSpan(text="Texto SPAN 1",
                        url='https://www.google.com',
                        style=estilo_span1),
            ft.TextSpan(text="Texto SPAN 2",
                        style=ft.TextStyle(
                            color=ft.Colors.RED_900,
                            font_family="Arial",
                        )),
        ],
    )

    # Adiciona objetos de texto e etc à página, (ao adicionar a interface atualiza automaticamente)
    page.add(
        ft.Text(value="Hello World"),
        ft.Container(ft.Text("Hello World 2"), bgcolor=ft.Colors.BLUE_50), # Container com cor de fundo
        texto_teste,
        texto2_span
        )
    
    # Atualiza a página para refletir as mudanças, usado para atualizar dinamicamente apos a interface criada
    # page.update()

# Inicia a aplicação e usa a função main como o ponto inicial para montar a interface.
ft.app(target=main)
flet_imagens_icones.py
import flet as ft

def main(page: ft.Page):
    page.theme_mode = ft.ThemeMode.SYSTEM
    page.padding = 50

    # IMAGEM UNICA
    img = ft.Image(
        src="https://www.w3schools.com/w3images/lights.jpg",
        border_radius=ft.border_radius.all(40),
        tooltip="Minha imagem"
    )

    # CARROSEL DE IMAGENS EM LINHA
    # Cria uma linha horizontal de elementos
    images_em_linha = ft.Row(expand=1,wrap=False, scroll="always")
    for i in range(0, 30):
        # Esse trecho adiciona elementos dinamicamente à linha (Row).
        images_em_linha.controls.append(
            ft.Image(
                src=f"https://picsum.photos/200/200?{i}",
                width=200,
                height=200,
                # como a imagem se encaixa dentro do tamanho, NONE = tamanho original (não redimensiona), podendo vazar fora da moldura.
                fit=ft.ImageFit.NONE,
                # Isso define se a imagem vai se repetir para preencher o espaço.
                repeat=ft.ImageRepeat.NO_REPEAT,
                border_radius=ft.border_radius.all(40)
            )
        )

    # Adicionando Icones
    icons_row = ft.Row(
        controls=[
            ft.Icon(name=ft.Icons.FAVORITE, color=ft.Colors.PINK, size=30),
            ft.Icon(name=ft.Icons.AUDIO_FILE, color=ft.Colors.GREEN, size=30),
            ft.Icon(name=ft.Icons.BEACH_ACCESS, color=ft.Colors.BLUE, size=30),
            ft.Icon(name="settings", color='#c1c1c1', size=30),
        ],
        alignment=ft.MainAxisAlignment.CENTER,
        spacing=20
    )
    page.add(
        # img,
        images_em_linha,
        ft.Column(
            controls=[icons_row],
        )
    )

ft.app(target=main)

Parâmetro Valor O que faz
expand=1 1 Faz o Row expandir para ocupar o espaço disponível dentro do pai
wrap=False False Impede que os elementos "quebrem linha" — ou seja, eles continuam na mesma linha mesmo se ultrapassarem o tamanho da tela
scroll="always" "always" Ativa a barra de rolagem horizontal, sempre visível (ideal pro carrossel!)

botoes.py
import flet as ft

def main(page:ft.Page):
    botao_elevado = ft.ElevatedButton(text="Botão Simples")
    botao_desativado = ft.ElevatedButton(text="Botão Desativado", disabled=True)
    botao_icone = ft.ElevatedButton(text="Botão com icone", icon="access_time")
    botao_icone_colorido = ft.ElevatedButton(text="Botão com icone colorido", icon="park_rounded", icon_color="green400")
    botao_conteudo_customizado = ft.ElevatedButton(
        width=150,
        content=ft.Row([
            ft.Icon(name=ft.Icons.FAVORITE, color="pink"),
            ft.Icon(name=ft.Icons.BEACH_ACCESS, color="blue"),
            ft.Icon(name=ft.Icons.AUDIO_FILE, color="green"),
        ])
    )
    botao_texto_composto = ft.ElevatedButton(
        content=ft.Container(
            content= ft.Column(
                [
                    ft.Text("Botão Composto", size=20),
                    ft.Text("Segundo Texto")
                ],
                alignment=ft.MainAxisAlignment.CENTER,
                spacing=5
            ),
            padding=ft.padding.all(10)
        )
    )

    def button_clicked(e):
        botao_evento.data += 1
        texto_evento.value = f"O botão acima foi clicado {botao_evento.data} vezes"
        page.update()
    
    botao_evento = ft.ElevatedButton(text="Botão com evento", on_click=button_clicked, data=0)
    texto_evento = ft.Text()
    
    page.add(
        botao_elevado,
        botao_desativado,
        botao_icone,
        botao_icone_colorido,
        botao_evento,
        texto_evento,
        botao_conteudo_customizado,
        botao_texto_composto
    )

ft.app(target=main)
barra_progresso.py
import flet as ft
from time import sleep

def main(page:ft.Page):
    barra_progresso = ft.ProgressBar(width=400)
    texto_barra_progresso = ft.Text("Progresso Linear", theme_style="headlineSmall")
    barra_indeterminada =  ft.ProgressBar(width=400, color="amber", bgcolor="#eeeeee")
    texto_barra_indeterminada = ft.Text("Progresso Indeterminado", theme_style="headlineSmall")
    barra_fixa =  ft.ProgressBar(width=400, color="purple", bgcolor="#eeeeee", value=0.3)
    texto_barra_fixa = ft.Text("Barra Fixa em 30%", theme_style="headlineSmall")
    barra_cupertino = ft.CupertinoActivityIndicator(
        radius=50,
        color=ft.Colors.RED,
        animating=True
    )

    page.add(
        # Coloco os textos e as barras em uma unica coluna (ficar um abaixo do outro), mas sem column também apareceria na ordem que colocar
        ft.Column([
                texto_barra_progresso, 
                ft.Text("Aguarde..."), 
                barra_progresso, 
                texto_barra_indeterminada, 
                barra_indeterminada, 
                texto_barra_fixa, 
                barra_fixa,
                barra_cupertino,
                ]),
    )

    for i in range(0,101):
        barra_progresso.value = i*0.01
        sleep(0.1)
        page.update()

ft.app(target=main)
inputs.py
import flet as ft

def main(page: ft.Page):
    page.title = "Exemplos de Inputs"
    page.scroll = "auto"
    page.padding = 20

    # Campo de texto simples
    nome_input = ft.TextField(
        label="Nome",
        hint_text="Digite seu nome",
        width=300
    )

    # Campo de texto com senha
    senha_input = ft.TextField(
        label="Senha",
        hint_text="Digite sua senha",
        password=True,
        can_reveal_password=True,
        width=300
    )

    # Campo numérico
    idade_input = ft.TextField(
        label="Idade",
        hint_text="Digite sua idade",
        keyboard_type=ft.KeyboardType.NUMBER,
        width=150
    )

    # Caixa de seleção (dropdown)
    genero_select = ft.Dropdown(
        label="Gênero",
        width=300,
        options=[
            ft.dropdown.Option("Masculino"),
            ft.dropdown.Option("Feminino"),
            ft.dropdown.Option("Outro"),
        ]
    )

    # Caixa de verificação (checkbox)
    checkbox_novidades = ft.Checkbox(
        label="Desejo receber novidades por e-mail",
        value=False, 
        on_change=lambda e: print(f"Checkbox marcado?: {e.control.value}")
    )

    # Switch (toggle)
    modo_escuro_switch = ft.Switch(label="Modo escuro")

    # Botão
    botao_enviar = ft.ElevatedButton(text="Enviar", on_click=lambda e: print("Formulário enviado"))

    # Agrupando tudo numa coluna com espaçamento
    page.add(
        ft.Column(
            controls=[
                ft.Text("Formulário de Cadastro", theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM),
                nome_input,
                senha_input,
                idade_input,
                genero_select,
                checkbox_novidades,
                modo_escuro_switch,
                botao_enviar
            ],
            spacing=15,
            alignment=ft.MainAxisAlignment.START,
        )
    )

ft.app(target=main)
alerts_banners.py
import flet as ft

# Função principal que será executada ao iniciar o app
def main(page: ft.Page):
    # Alinha horizontalmente os elementos no centro da página (eixo cruzado = vertical, pois Flet usa eixo principal como vertical em Column)
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER

    # Estilo reutilizável para os botões do banner
    action_button_style = ft.ButtonStyle(color=ft.colors.BLUE)

    # Função chamada ao clicar em um dos botões do banner
    def close_banner(e):
        # Fecha o banner
        page.close(banner)
        # Adiciona um texto à página indicando qual botão foi clicado (usa o texto do botão: e.control.text)
        page.add(ft.Text("Clicado: " + e.control.text))

    # Criação do banner que aparecerá na parte superior da página
    banner = ft.Banner(
        bgcolor=ft.colors.AMBER_100,  # Cor de fundo do banner
        leading=ft.Icon(              # Ícone à esquerda do banner
            ft.icons.WARNING_AMBER_ROUNDED,
            color=ft.Colors.AMBER,
            size=40
        ),
        content=ft.Text(              # Texto principal do banner
            value="OOps, there were some errors while trying to delete the file.",
            color=ft.colors.BLACK
        ),
        actions=[                     # Botões de ação dentro do banner
            ft.TextButton(text="Retry", style=action_button_style, on_click=close_banner),
            ft.TextButton(text="Ignore", style=action_button_style, on_click=close_banner),
            ft.TextButton(text="Cancel", style=action_button_style, on_click=close_banner)
        ]
    )

    # Função para mostrar um diálogo não-modal (o usuário pode interagir com a página enquanto ele está aberto)
    def show_non_modal_dialog(e):
        # Cria um AlertDialog não-modal
        dlg = ft.AlertDialog(
            title=ft.Text("Hi, this is a non-modal dialog!"),
            on_dismiss=lambda e: page.add(ft.Text("non-modal dialog dismissed"))  # Quando o usuário fecha, adiciona texto à página
        )
        # Abre o diálogo
        page.open(dlg)

    # Função para mostrar um diálogo modal (o usuário NÃO pode interagir com o restante da página até fechá-lo)
    def show_modal_dialog(e):
        # Função chamada quando um botão dentro do diálogo for clicado
        def handle_close(e):
            page.close(dialog_modal)  # Fecha o diálogo
            page.add(ft.Text(f"Modal dialog closed with action: {e.control.text}"))  # Mostra qual botão foi clicado

        # Cria o diálogo modal
        dialog_modal = ft.AlertDialog(
            modal=True,  # Torna o diálogo modal (bloqueia interações fora dele)
            title=ft.Text("Please Confirm?"),  # Título do diálogo
            content=ft.Text("Do you Really want to delete all those files?"),  # Texto de corpo
            actions=[  # Botões de ação
                ft.TextButton("Yes", on_click=handle_close),
                ft.TextButton("No", on_click=handle_close)
            ],
            actions_alignment=ft.MainAxisAlignment.END,  # Alinha os botões à direita
            on_dismiss=lambda e: page.add(ft.Text("Modal dialog dismissed"))  # Mensagem caso o diálogo seja fechado de outra forma
        )

        # Abre o diálogo modal
        page.open(dialog_modal)

    # Adiciona os botões principais na página
    page.add(
        # Botão para abrir o diálogo não-modal
        ft.ElevatedButton("Open non-modal dialog", on_click=show_non_modal_dialog),
        # Botão para abrir o diálogo modal
        ft.ElevatedButton("Open modal dialog", on_click=show_modal_dialog),
        # Botão para mostrar o banner
        ft.ElevatedButton("Show Banner", on_click=lambda e: page.open(banner))
    )

# Inicializa o aplicativo chamando a função main
ft.app(target=main)
navegation_bar.py
# Importa o módulo Flet, que é usado para criar interfaces gráficas em Python.
import flet as ft

# Função principal que recebe a página como argumento.
def main(page: ft.Page):
    
    # ----------- ABAS COM ÍCONES (NavigationBar) ----------- #

    # Define o título da janela do app
    page.title = "NavigationBar"

    # Cria uma barra de navegação na parte inferior da tela com 3 abas
    page.navigation_bar = ft.NavigationBar(
        destinations=[
            # Primeira aba: ícone de exploração
            ft.NavigationBarDestination(icon=ft.icons.EXPLORE, label="Explore"),

            # Segunda aba: ícone de transporte
            ft.NavigationBarDestination(icon=ft.icons.COMMUTE, label="Commute"),

            # Terceira aba: muda o ícone quando está selecionado
            ft.NavigationBarDestination(
                icon=ft.icons.BOOKMARK_BORDER,  # ícone padrão
                label="Explore",
                selected_icon=ft.icons.BOOKMARK  # ícone quando selecionado
            ),
        ]
    )

    # Adiciona um texto simples no corpo da página
    page.add(ft.Text("Body"))

    # ----------- BARRA HAMBÚRGUER (NavigationDrawer) ----------- #

    # Centraliza horizontalmente os elementos adicionados à página
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER

    # Função que será chamada quando o drawer for fechado (dismissed)
    def handle_dismissal(e):
        # Adiciona um texto na tela indicando que o drawer foi fechado
        page.add(ft.Text("Drawer dismissed"))

    # Função chamada quando o usuário muda a seleção no drawer
    def handle_change(e):
        # Mostra na tela o índice do item selecionado
        page.add(ft.Text(f"Selected Index changed: {e.selected_index}"))

    # Cria o drawer (menu lateral) com itens de navegação
    drawer = ft.NavigationDrawer(
        on_dismiss=handle_dismissal,  # chama a função ao fechar o drawer
        on_change=handle_change,      # chama a função ao selecionar item

        controls = [  # lista de itens exibidos no drawer
            ft.Container(height=12),  # espaçamento superior

            # Primeiro item do drawer
            ft.NavigationDrawerDestination(
                label="Item 1",
                icon_content=ft.Icon(ft.icons.DOOR_BACK_DOOR_OUTLINED),  # ícone padrão
                selected_icon=ft.Icons.DOOR_BACK_DOOR                     # ícone quando selecionado
            ),

            # Linha divisória
            ft.Divider(thickness=2),

            # Segundo item do drawer
            ft.NavigationDrawerDestination(
                label="Item 2",
                icon_content=ft.Icon(ft.icons.MAIL_OUTLINED),
                selected_icon=ft.Icons.MAIL
            ),

            # Terceiro item do drawer
            ft.NavigationDrawerDestination(
                label="Item 3",
                icon_content=ft.Icon(ft.icons.PHONE_OUTLINED),
                selected_icon=ft.Icons.PHONE
            ),
        ]
    )
    
    # Adiciona um botão na tela que abre o drawer ao ser clicado
    page.add(ft.ElevatedButton("Show drawer", on_click=lambda e: page.open(drawer)))

# Inicia o aplicativo executando a função main
ft.app(target=main)
expense_panel_list.py
import flet as ft

def main(page: ft.Page):
    # Título da página
    page.title = "Exemplo de ExpansionPanelList"
    
    # Função chamada ao abrir ou fechar o painel
    def on_change(e):
        page.add(ft.Text(f"Painel {e.control.selected_index + 1} foi clicado"))

    # Cria a lista de painéis expansíveis
    expansion_panel_list = ft.ExpansionPanelList(
        # Define o comportamento quando um painel é clicado
        expand_icon_color=ft.colors.BLUE,
        divider_color=ft.colors.GREY,
        elevation=3,
        controls=[
            # Primeiro painel
            ft.ExpansionPanel(
                header=ft.Text("Painel 1"),
                content=ft.Text("Conteúdo do painel 1"),
                expanded=False,
            ),
            # Segundo painel
            ft.ExpansionPanel(
                header=ft.Text("Painel 2"),
                content=ft.Text("Conteúdo do painel 2"),
                expanded=False,
            ),
            # Terceiro painel
            ft.ExpansionPanel(
                header=ft.Text("Painel 3"),
                content=ft.Text("Conteúdo do painel 3"),
                expanded=False,
            ),
        ],
        on_change=on_change  # Chama a função quando um painel muda de estado
    )

    # Adiciona à página
    page.add(expansion_panel_list)

ft.app(target=main)
card.py
# Importa o módulo Flet, usado para criar interfaces gráficas com Python
import flet as ft

# Define a função principal que recebe a página como argumento
def main(page: ft.Page):
    # Cria o conteúdo do card, usando uma coluna (empilha os elementos verticalmente)
    card_content = ft.Column(
        [
            # Cria um ListTile (componente com ícone, título e subtítulo) para o cabeçalho do card
            ft.ListTile(
                leading=ft.Icon(ft.Icons.CAKE),  # Ícone de bolo (símbolo de aniversário)
                title=ft.Text("Feliz aniversário!", size=25, weight="bold"),  # Título em negrito e fonte maior
                subtitle=ft.Text("Que seu dia seja repleto de alegrias, risadas e muito amor.")  # Texto abaixo do título
            ),
            
            # Cria uma linha para conter os botões "Compartilhar" e "Enviar votos"
            ft.Row(
                [
                    # Primeiro botão: "Compartilhar"
                    ft.TextButton(
                        "Compartilhar",
                        # Quando clicado, exibe uma mensagem na tela com cor verde
                        on_click=lambda _: page.add(
                            ft.Text("Mensagem compartilhada com sucesso", color=ft.colors.GREEN_600)
                        ),
                    ),
                    # Segundo botão: "Enviar votos" (sem ação definida)
                    ft.TextButton("Enviar votos")
                ]
            )
        ],
        # Alinha os itens da coluna ao final (parte inferior do card)
        alignment=ft.MainAxisAlignment.END
    )

    # Adiciona um Card à página com o conteúdo definido acima
    page.add(
        ft.Card(
            content=ft.Container(
                content=card_content,  # Insere o conteúdo dentro do card
                width=400,             # Define a largura do card
                padding=20             # Espaçamento interno (padding) de 20px em todos os lados
            )
        )
    )

# Executa o aplicativo Flet e chama a função 'main' como ponto de entrada
ft.app(target=main)
gridview.py
import flet as ft

def main(page: ft.Page):
    page.title = "Exemplo de GridView com Imagens"
    page.scroll = "auto"  # Permite rolagem automática se os itens ultrapassarem a altura da tela

    # Lista de URLs de imagens
    imagens = [
        "https://picsum.photos/200/200?1",
        "https://picsum.photos/200/200?2",
        "https://picsum.photos/200/200?3",
        "https://picsum.photos/200/200?4",
        "https://picsum.photos/200/200?5",
        "https://picsum.photos/200/200?6"
    ]

    # Cria os containers com imagens (dentro de uma lista por compreensão)
    itens_grid = [
        ft.Container(
            content=ft.Image(src=url, fit=ft.ImageFit.COVER),
            width=150,
            height=150,
            border_radius=10,
            bgcolor=ft.colors.GREY_200,
            padding=5
        )
        for url in imagens
    ]

    # Cria um GridView para exibir os itens
    grid = ft.GridView(
        expand=True,       # Ocupa o espaço disponível
        runs_count=3,      # Número de colunas (itens por linha)
        max_extent=200,    # Largura máxima por item (controla a quebra de linha automaticamente)
        child_aspect_ratio=1.0,  # Mantém o aspecto quadrado
        spacing=10,        # Espaço horizontal entre itens
        run_spacing=10,    # Espaço vertical entre linhas
        controls=itens_grid  # Adiciona os itens ao grid
    )

    # Adiciona o grid à página
    page.add(grid)

# Executa o app
ft.app(target=main)