Tutorial Tkinter OptionMenu
Aprenda a construir menus suspensos com Tkinter OptionMenu: callbacks, atualizações ao vivo, adicionar/remover opções, dicas de estilo e um exemplo completo executável.
Progresso do Tutorial
1 Introdução ao Tkinter OptionMenu
OptionMenu no Tkinter cria uma lista suspensa vinculada a uma variável. É útil para escolhas como temas, idiomas ou qualquer conjunto finito de opções. Internamente, ele armazena o valor selecionado em uma variável e pode chamar uma função sempre que o usuário selecionar um novo item.
Ao final deste guia, você terá um aplicativo seletor de temas executável que atualiza um painel de pré-visualização e exibe uma mensagem com o tema selecionado.
2 Pré-requisitos: Python e Tkinter
Você precisará do Python 3.7+. O Tkinter vem com a maioria das instalações Python no macOS e Windows. Se estiver no Linux, instale o pacote tk:
# Debian/Ubuntu
sudo apt-get install python3-tk
Verifique se o Tkinter está disponível:
python -m tkinter
Se uma pequena janela se abrir, o Tkinter está funcionando.
3 OptionMenu Mínimo: As Peças Centrais
Você precisa de três blocos de construção: uma variável Tkinter (geralmente StringVar), uma lista de opções e um OptionMenu conectado à variável.
import tkinter as tk
root = tk.Tk()
root.title("OptionMenu Mínimo")
# 1) Variável para armazenar a seleção atual
choice = tk.StringVar(value="A")
# 2) Criar o OptionMenu, passando a variável e as opções
menu = tk.OptionMenu(root, choice, "A", "B", "C")
menu.pack(padx=20, pady=20)
root.mainloop()
- StringVar mantém o valor atual sincronizado com o dropdown.
value="A"define o padrão; sem ele, a primeira opção é geralmente selecionada.- Atualizar
choice.set("B")moverá a seleção do OptionMenu programaticamente.
4 Reagir a Mudanças: Adicionar um Callback
Passe uma função para o argumento command. O Tkinter a chama com o valor recém-selecionado.
import tkinter as tk
from tkinter import messagebox
def on_select(value):
messagebox.showinfo("Seleção", f"Você escolheu: {value}")
root = tk.Tk()
choice = tk.StringVar(value="Ocean")
menu = tk.OptionMenu(root, choice, "Ocean", "Forest", "Sunset", command=on_select)
menu.pack(padx=20, pady=20)
root.mainloop()
Use callbacks para sincronizar outros widgets, acionar validação ou atualizar um painel de informações.
5 Construa uma Pré-visualização ao Vivo (Como Nosso Exemplo)
Armazene os dados do tema, em seguida, atualize um painel de pré-visualização sempre que a seleção mudar.
import tkinter as tk
from tkinter import messagebox
themes = {
"Ocean": {"primary": "#1a73e8", "secondary": "#4285f4", "text": "white"},
"Forest": {"primary": "#2e7d32", "secondary": "#4caf50", "text": "white"},
"Sunset": {"primary": "#d32f2f", "secondary": "#f44336", "text": "white"},
}
def update_preview(theme_name):
t = themes[theme_name]
preview.configure(bg=t["primary"])
title.configure(bg=t["primary"], fg=t["text"])
button.configure(bg=t["secondary"], fg=t["text"], activebackground=t["primary"], activeforeground=t["text"])
root = tk.Tk()
choice = tk.StringVar(value="Ocean")
menu = tk.OptionMenu(root, choice, *themes.keys(), command=lambda v: update_preview(v))
menu.pack(padx=20, pady=10)
preview = tk.Frame(root, width=220, height=120, relief="raised", bd=2)
preview.pack(pady=10)
title = tk.Label(preview, text="Pré-visualização do Tema")
title.pack(pady=6)
button = tk.Button(preview, text="OK", command=lambda: messagebox.showinfo("Tema", f"{choice.get()}"))
button.pack(pady=6)
update_preview(choice.get())
root.mainloop()
6 Alterando Opções e Desabilitando Itens
O OptionMenu não expõe uma API de remover/adicionar integrada. A abordagem usual é reconstruir o menu com as opções atualizadas e preservar a seleção atual.
def rebuild_options(new_options, keep_value=True):
current = choice.get() if keep_value else new_options[0]
menu["menu"].delete(0, "end")
for opt in new_options:
menu["menu"].add_command(label=opt, command=lambda v=opt: choice.set(v))
choice.set(current)
# Comece com estes
choices = ["A", "B", "C"]
choice = tk.StringVar(value="B")
menu = tk.OptionMenu(root, choice, *choices)
menu.pack(padx=20, pady=20)
# Mais tarde, remova "B"
rebuild_options([opt for opt in choices if opt != "B"])
Para desabilitar um item específico, coloque-o em um submenu de cascata e use state="disabled". Remover ou reordenar é mais simples com uma reconstrução.
7 Estilização e Layout: Dominando a Aparência
Use configure(width=...) para controlar a largura. Para fontes e cores, defina atributos no menu e em seu widget de menu interno. Combinar ttk.Frame com tk.OptionMenu pode arrumar o espaçamento.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
frame = ttk.Frame(root, padding=16)
frame.pack()
choice = tk.StringVar(value="Ocean")
menu = tk.OptionMenu(frame, choice, "Ocean", "Forest", "Sunset")
menu.configure(width=14, font=("Helvetica", 11))
menu["menu"].configure(font=("Helvetica", 11))
ttk.Label(frame, text="Escolha um tema:").pack(anchor="w", pady=(0, 6))
menu.pack(anchor="w")
root.mainloop()
8 Armadilhas e Gotchas Comuns
- Esquecer de definir um valor inicial pode resultar em uma seleção vazia.
- Callbacks recebem o novo valor, não a variável. Use a variável se precisar de um estado mais amplo.
- OptionMenu não tem uma API direta de "remover opção" — reconstrua através do widget interno
menu. - Misturar
tkettkpode produzir diferenças sutis de estilo. - Em alguns sistemas, alterar fontes no menu interno não tem efeito devido à renderização da plataforma.
9 Exercício: Adicionar e Remover Opções
Estenda o exemplo mínimo: adicione um campo de entrada e um botão que insira a opção digitada no menu (se não estiver presente) e a selecione. Em seguida, adicione outro botão para remover a opção atualmente selecionada.
import tkinter as tk
root = tk.Tk()
choice = tk.StringVar(value="A")
options = ["A", "B", "C"]
menu = tk.OptionMenu(root, choice, *options)
menu.pack(padx=16, pady=16)
entry = tk.Entry(root)
entry.pack(padx=16)
def add_option():
val = entry.get().strip()
if not val or val in options:
return
options.append(val)
menu["menu"].add_command(label=val, command=lambda v=val: choice.set(val))
choice.set(val)
def remove_selected():
val = choice.get()
if val not in options:
return
options.remove(val)
rebuild_options()
tk.Button(root, text="Adicionar", command=add_option).pack(pady=6)
tk.Button(root, text="Remover Selecionado", command=remove_selected).pack(pady=6)
def rebuild_options():
current = choice.get()
menu["menu"].delete(0, "end")
for opt in options:
menu["menu"].add_command(label=opt, command=lambda v=opt: choice.set(v))
if options:
choice.set(current if current in options else options[0])
root.mainloop()
10 Projeto Completo: Seletor de Temas com Pré-visualização
Copie isso em um arquivo chamado theme_selector.py e execute com python theme_selector.py.
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
class ColorThemeSelector(tk.Tk):
def __init__(self):
super().__init__()
# Configura a janela principal
self.title("Exemplo OptionMenu")
self.geometry("400x300")
self.configure(padx=20, pady=20)
# Define os temas de cores
self.color_themes = {
"Ocean": {"primary": "#1a73e8", "secondary": "#4285f4", "text": "white"},
"Forest": {"primary": "#2e7d32", "secondary": "#4caf50", "text": "white"},
"Sunset": {"primary": "#d32f2f", "secondary": "#f44336", "text": "white"},
"Lavender": {"primary": "#7b1fa2", "secondary": "#9c27b0", "text": "white"}
}
# Cria e configura um frame
self.main_frame = ttk.Frame(self)
self.main_frame.pack(expand=True, fill='both')
# Cria uma StringVar para armazenar a opção selecionada
self.selected_theme = tk.StringVar()
self.selected_theme.set("Ocean") # Define o valor padrão
# Cria um rótulo
self.label = ttk.Label(
self.main_frame,
text="Selecione Seu Tema de Cores:",
font=('Helvetica', 12)
)
self.label.pack(pady=10)
# Cria o OptionMenu
self.theme_menu = tk.OptionMenu(
self.main_frame,
self.selected_theme,
*self.color_themes.keys(),
command=self.update_preview
)
self.theme_menu.configure(width=15)
self.theme_menu.pack(pady=10)
# Cria um frame de pré-visualização
self.preview_frame = tk.Frame(
self.main_frame,
width=200,
height=100,
relief="raised",
bd=2
)
self.preview_frame.pack(pady=20)
# Cria elementos de pré-visualização
self.preview_title = tk.Label(
self.preview_frame,
text="Pré-visualização do Tema",
font=('Helvetica', 10)
)
self.preview_title.pack(pady=5)
self.preview_button = tk.Button(
self.preview_frame,
text="Botão de Amostra",
command=self.show_selection
)
self.preview_button.pack(pady=10)
# Inicializa a pré-visualização
self.update_preview()
def update_preview(self, *args):
"""Atualiza o frame de pré-visualização com as cores do tema selecionado"""
theme = self.color_themes[self.selected_theme.get()]
# Atualiza o fundo do frame de pré-visualização
self.preview_frame.configure(bg=theme["primary"])
self.preview_title.configure(
bg=theme["primary"],
fg=theme["text"]
)
self.preview_button.configure(
bg=theme["secondary"],
fg=theme["text"],
activebackground=theme["primary"],
activeforeground=theme["text"]
)
def show_selection(self):
"""Exibe uma caixa de mensagem com a seleção atual"""
messagebox.showinfo(
"Tema Selecionado",
f"Você selecionou o tema {self.selected_theme.get()}!"
)
if __name__ == "__main__":
app = ColorThemeSelector()
app.mainloop()
Execute-o: python theme_selector.py. Tente mudar os temas — observe a pré-visualização atualizar em tempo real.