Salta el contingut

Interfícies Gràfiques amb Tkinter

Introducció

Tkinter és la biblioteca estàndard de Python per crear interfícies gràfiques d'usuari (GUI). Forma part de la instal·lació de Python i no requereix cap dependència externa. Internament fa servir la biblioteca Tk, disponible a Windows, macOS i Linux.

Els exemples d'aquest mòdul provenen de la sèrie de vídeos "Tkinter Basics" d'Alan D Moore i del repositori Tkinter-By-Example. Al llarg dels vídeos es construeix progressivament una aplicació de diari personal (My Diary) que va incorporant nous conceptes en cada lliurament.

Pots ampliar els teus coneixements amb el llibre d'Alan: Python GUI Programming with Tkinter.


Estructura dels exemples

Tots els exemples es troben a pys/ organitzats per vídeo:

Carpeta Conceptes principals
pys/Video1/ Finestra, widgets bàsics, layout grid
pys/Video2/ Funcions, callbacks, barra d'estat, guardar fitxer
pys/Video3/ Variables de control (StringVar, BooleanVar), trace
pys/Video4/ Frame, LabelFrame, Scrollbar
pys/Video5/ Diàlegs (messagebox, simpledialog, filedialog)
pys/Video6/ Menú (Menu), mida de lletra dinàmica
pys/Video7/ Radiobutton, color de fons, marca de data
pys/Video8/ ttk: widgets amb tema, Notebook, Combobox, Treeview
pys/Video9/ ttk.Style: personalització visual i temes

Conceptes per vídeo

Video 1 — Finestra i widgets bàsics

  • Crear la finestra principal amb tk.Tk()
  • Configurar títol, mida i pes de files/columnes amb columnconfigure / rowconfigure
  • Widgets: Label, Entry, Listbox, Text, Button
  • Sistema de layout grid amb opcions sticky, padx, pady, columnspan
import tkinter as tk

root = tk.Tk()
root.title('My Diary')
root.geometry('800x600')
root.columnconfigure(1, weight=1)
root.rowconfigure(2, weight=1)

tk.Label(root, text='Subject: ').grid(sticky='we', padx=5, pady=5)
tk.Entry(root).grid(row=0, column=1, sticky=tk.E + tk.W)

root.mainloop()

Video 2 — Funcions i desar fitxers

  • Associar una funció a un botó amb configure(command=...)
  • Llegir el contingut dels widgets amb .get() i .get('1.0', tk.END)
  • Barra d'estat dinàmica amb Label
  • Desar dades en un fitxer de text
def save():
    subject = subject_inp.get()
    message = message_inp.get('1.0', tk.END)
    with open(f'{subject}.txt', 'w') as fh:
        fh.write(message)
    status_bar.configure(text='Fitxer desat')

save_btn.configure(command=save)

Video 3 — Variables de control i trace

  • StringVar, BooleanVar, IntVar: variables observables vinculades a widgets
  • OptionMenu per a llistes desplegables
  • Checkbutton per a opcions booleanes
  • trace_add('write', callback) per reaccionar a canvis de valor en temps real
subject_var = tk.StringVar()
cat_var = tk.StringVar()

def check_filename(*args):
    filename = f'{cat_var.get()} - {subject_var.get()}.txt'
    if Path(filename).exists():
        status_var.set(f'AVÍS: {filename} ja existeix!')

subject_var.trace_add('write', check_filename)
cat_var.trace_add('write', check_filename)

Video 4 — Frame, LabelFrame i Scrollbar

  • Frame per agrupar widgets i simplificar el layout
  • LabelFrame per a grups amb títol visible
  • Scrollbar vinculada a un widget Text amb yscrollcommand i yview
message_frame = tk.LabelFrame(root, text='Missatge')
message_frame.columnconfigure(0, weight=1)
message_inp = tk.Text(message_frame)
message_inp.grid(sticky='nesw')

scrollbar = tk.Scrollbar(message_frame)
scrollbar.grid(row=0, column=1, sticky='nse')

scrollbar.configure(command=message_inp.yview)
message_inp.configure(yscrollcommand=scrollbar.set)

Video 5 — Diàlegs estàndard

  • tkinter.messagebox: showinfo, askokcancel
  • tkinter.simpledialog: askstring per demanar text a l'usuari
  • tkinter.filedialog: askopenfilename per seleccionar un fitxer
  • Obrir i desar fitxers amb diàlegs natius del sistema operatiu
from tkinter import messagebox as tkmb
from tkinter import simpledialog as tksd
from tkinter import filedialog as tkfd

file_path = tkfd.askopenfilename(
    title='Selecciona un fitxer',
    filetypes=[('Text', '*.txt'), ('Secret', '*.secret')]
)

password = tksd.askstring('Contrasenya', 'Introdueix la contrasenya:')

tkmb.showinfo('Desat', f'Fitxer desat correctament')

Video 6 — Menú i mida de lletra

  • tk.Menu per crear la barra de menú principal
  • add_cascade, add_command, add_separator per estructurar el menú
  • add_checkbutton i add_radiobutton per a opcions dins del menú
  • Menús en cascada (submenús) amb add_cascade
  • Canvi de mida de lletra del Text amb configure(font=...)
menu = tk.Menu(root)
root.configure(menu=menu)

file_menu = tk.Menu(menu, tearoff=0)
menu.add_cascade(label='Fitxer', menu=file_menu)
file_menu.add_command(label='Obre', command=open_file)
file_menu.add_command(label='Desa', command=save)
file_menu.add_separator()
file_menu.add_command(label='Surt', command=root.destroy)

size_menu = tk.Menu(options_menu, tearoff=0)
for size in range(6, 33, 2):
    size_menu.add_radiobutton(label=size, value=size, variable=font_size)

Video 7 — Radiobutton i estructura avançada

  • Radiobutton per triar una opció d'un grup (variable compartida)
  • pack per disposar widgets horitzontalment dins d'un frame
  • Afegir marca de data/hora al missatge en desar
  • Subframe general del formulari per millorar el layout
datestamp_var = tk.StringVar(value='None')
datestamp_frame = tk.Frame(form_frame)

for value in ('None', 'Date', 'Date+Time'):
    tk.Radiobutton(
        datestamp_frame,
        text=value,
        value=value,
        variable=datestamp_var
    ).pack(side=tk.LEFT)

Video 8 — ttk: widgets amb tema i Notebook

El mòdul tkinter.ttk proporciona widgets amb estil natiu del sistema operatiu.

  • ttk.Notebook: contenidor de pestanyes navegables
  • ttk.Frame, ttk.Label, ttk.Entry, ttk.Button, ttk.Checkbutton, ttk.Radiobutton
  • ttk.Combobox com a alternativa millorada a OptionMenu
  • ttk.Separator per separar seccions visualment
  • ttk.Treeview per mostrar dades en format taula amb columnes ordenables
from tkinter import ttk

notebook = ttk.Notebook(root)
notebook.grid(sticky='nesw', padx=5, pady=5)
notebook.enable_traversal()

form_frame = ttk.Frame(notebook)
notebook.add(form_frame, text='Entrada del diari', underline=0)

files_frame = ttk.Frame(notebook)
notebook.add(files_frame, text='Fitxers', underline=0)

# Treeview amb columnes
file_tree = ttk.Treeview(files_frame)
ft_columns = ('Nom', 'Tipus', 'Creat')
file_tree.configure(columns=ft_columns, show='headings')

Video 9 — ttk.Style: personalització visual i temes

  • ttk.Style per definir l'aparença dels widgets ttk
  • style.configure('TLabel', font=...) per estilitzar per tipus de widget
  • style.map(...) per canviar l'estil segons l'estat (selected, active, disabled)
  • Estils personalitzats com 'Status.TLabel'
  • style.theme_names() per llistar els temes disponibles
  • style.theme_use(theme) per canviar el tema en temps d'execució
style = ttk.Style()

style.configure('TLabel', font='Arial 18 bold')
style.configure('TCheckbutton', font='Arial 16 bold', background='silver')
style.configure('Status.TLabel', font='Arial 12', background='white')

style.map(
    'TCheckbutton',
    background=[
        ('selected', 'pink'),
        ('active', 'red'),
        ('disabled', 'grey')
    ]
)

# Canviar tema dinàmicament
theme_var = tk.StringVar()
theme_var.trace_add('write', lambda *a: style.theme_use(theme_var.get()))

Instal·lació

Tkinter ve inclòs amb Python. En algunes distribucions Linux cal instal·lar-lo per separat:

# Ubuntu/Debian
sudo apt install python3-tk

Execució dels exemples

python curs/014_PYGUI/pys/Video1/diary.py
python curs/014_PYGUI/pys/Video9/diary-ttk.py

Llicència

Tot el codi d'aquest repositori està llicenciat sota la llicència MIT.