fr –

Tutoriel Tkinter Python

2024-10-30
programmation, Python

Prérequis : Il faut être un peu à l'aise avec le Python, au moins les variables, fonctions, manipulation des chaînes de caractères. Si ce n'est pas le cas, France-IOI propose une introduction ludique au Python.

Tkinter est une bibliothèque d'interface graphique, qui permet de créer des fenêtres sous Linux, Windows et Mac. C'est une des plus simples à utiliser en Python. Seulement elle est un peu vieille et trop peu intuitive, d'où ce tutoriel qui peut servir de mini-référence.

Pour aller plus loin : TkDocs Tutorial (en anglais)

Ce tutoriel est disponible en PDF. Le code source et les commandes utilisées pour générer le PDF sont disponibles dans ce dépôt Git.

§Code de base

Créer une fenêtre vide :

import tkinter as tk
from tkinter import ttk

root = tk.Tk()

root.mainloop()

Ajouter des boutons dans la fenêtre :

import tkinter as tk
from tkinter import ttk

root = tk.Tk()

bt1 = ttk.Button(root, text="Bonjour")
bt1.grid(column=0, row=0)

bt2 = ttk.Button(root, text="Au revoir")
bt2.grid(column=1, row=0)

root.mainloop()

§Positionnement

On peut changer le nombre de colonnes ou de lignes occupées par un widget en ajoutant les paramètres columnspan ou rowspan en plus de column et row.

Pour coller un widget au bord de la grille, on peut ajouter sticky :

bt2.grid(column=1, row=0, sticky=(tk.W, tk.N))

sticky prend une liste de 0 à 4 éléments parmi :

§Redimensionner la fenêtre

Il faut indiquer quelles lignes et colonnes doivent changer de taille quand la fenêtre change de taille.

Dans cet exemple, ce sont la ligne 1 et la colonne 0.

root.rowconfigure(1, weight=1)
root.columnconfigure(0, weight=1)

On peut appeler plusieurs fois ces fonctions pour choisir plusieurs lignes et colonnes, et changer les weight pour modifier les proportions.

§Widgets

Tous les widgets doivent être positionnés avec grid, de la même manière que ci-dessus. Sans ça, ils ne seront pas affichés !

§Label

Juste du texte.

label = ttk.Label(root, text="Je suis un texte. Wow.")

On peut aussi modifier le texte plus tard :

label_text = tk.StringVar()
label["textvariable"] = label_text
label_text.set("Le nouveau texte. Tout ça pour ça !")

§Bouton

Un bouton qu'on peut cliquer.

def onclick():
	print("On a cliqué")

bt = ttk.Button(root, text="Cliquez-moi", command=onclick)

§Image

Un bouton ou un label peut afficher une image :

img = tk.PhotoImage(file='image.png')
label["image"] = img

§Entrée de texte

Boîte dans laquelle on peut écrire une ligne de texte.

text = tk.StringVar()
entry = ttk.Entry(root, textvariable=text)

Plus tard, on peut récupérer le texte :

print("L'utilisateur a écrit :", text.get())

§Entrée de texte multiligne

Zone dans laquelle on peut écrire du texte en plusieurs lignes.

text = tk.Text(root)

Il y a plusieurs méthodes pour interagir avec le texte :

print(text.get("1.0", "end")) # obtenir tout le texte
print(text.get("2.0", "8.0")) # le texte de la ligne 2 à la ligne 8
text.replace("1.0", "end", "le nouveau texte") # remplacer du texte
text.insert("1.0", "le nouveau texte") # insérer du texte
text.insert("1.0 +42 chars", "le nouveau texte")
text.insert("end -3 lines", "le nouveau texte")

Pour mettre en forme certaines parties du texte, on peut utiliser des tags :

text.tag_configure("fond_rouge", background="#ffaaaa")
text.tag_configure("insistance", foreground="#008800", underline=True)

text.insert("1.0", "ce texte sera sur fond rouge", "fond_rouge")
text.tag_add("insistance", "1.3", "1.8")

Liste de tous les styles possibles.

§Barre de défilement

Certains widgets (Text) peuvent défiler avec la molette, mais pour afficher la barre de défilement il faut un widget supplémentaire.

scroll = ttk.Scrollbar(root, orient=tk.VERTICAL, command=mon_widget_qui_défile.yview)
scroll.grid(column=1, row=0, sticky=(tk.N, tk.S, tk.E, tk.W))
mon_widget_qui_défile.configure(yscrollcommand=scroll.set)

§Cadre

Un cadre qui peut avoir une bordure et contenir d'autres widgets.

frame = ttk.Frame(root, borderwidth=5, relief="ridge", width=200, height=100)

Les options ne sont pas obligatoires.

Le cadre contient ses propres lignes et colonnes. Pour placer des widgets dedans, il suffit de remplacer root par frame en les créant.

§Barre de menus

La barre de menus en haut de la fenêtre.

root.option_add('*tearOff', False)
menubar = tk.Menu(root)
root['menu'] = menubar

menu_file = tk.Menu(menubar)
menu_edit = tk.Menu(menubar)

menubar.add_cascade(menu=menu_file, label='Fichier')
menubar.add_cascade(menu=menu_edit, label='Édition')

menu_file.add_command(label='Ouvrir', command=on_open)

§Canevas

Le canevas est une zone de dessin.

canvas = tk.Canvas(root, background='white')

On peut y dessiner des formes :

canvas.create_line(x1, y1, x2, y2)
canvas.create_line(x1, y1, x2, y2, fill="red", width=3, dash=6)
canvas.create_rectangle(x1, y1, x2, y2, fill="red", outline="blue")
canvas.create_oval(x1, y1, x2, y2, fill="red", outline="blue")

§Événements

Quand il se passe quelque chose sur un widget, un événement est généré. On peut écouter les événements de certains types, c'est-à-dire lancer une fonction quand l'action se produit.

Par exemple, on affiche des informations quand une touche du clavier est relâchée dans la zone de texte :

text = tk.Text(root)

def onrelease(event):
	print("On a frappé le clavier !")
	print(event)

text.bind("<KeyRelease>", onrelease)

On peut aussi utiliser les infos contenues dans l'événement, par exemple event.keycode.

§Liste des événements

§Dialogues

On peut ouvrir des fenêtres pour dire ou demander des choses.

§Fichiers

Demander où enregistrer un fichier, quel fichier ouvrir, choisir un dossier.

from tkinter import filedialog

filetypes = [
	("Texte", "*.txt"),
	("Image PNG", "*.png"),
	("Autre", "*.*")
]
chemin = tk.filedialog.asksaveasfilename(filetypes=filetypes)
print(chemin)

On peut remplacer asksaveasfilename par askopenfilename ou askdirectory.

§Couleur

Demander de choisir une couleur.

from tkinter import colorchooser

color = colorchooser.askcolor(initialcolor='black')
print(color)

On peut aussi indiquer la couleur initiale avec sa notation hexadécimale "#000000".