OUJOOD.COM
Le problème le plus frustrant avec les interfaces graphiques : un calcul long bloque l'interface et la fenêtre se fige. L'utilisateur ne peut plus cliquer, déplacer la fenêtre, ni voir de retour visuel. Deux outils Tkinter résolvent ce problème : after() pour les tâches courtes planifiées, et threading pour les opérations vraiment longues.
after() — planifier une action future
after(délai_ms, fonction) planifie un appel dans la boucle principale après un délai en millisecondes. La fenêtre reste réactive pendant l'attente :
import tkinter as tk
fenetre = tk.Tk()
fenetre.title("after() — exemple")
fenetre.geometry("340x160")
def message_temporaire():
label.config(text="Message envoyé !", fg="#2e7d32")
# Effacer le message après 2 secondes
fenetre.after(2000, lambda: label.config(text="", fg="black"))
tk.Button(fenetre, text="Envoyer", command=message_temporaire).pack(pady=30)
label = tk.Label(fenetre, text="", font=("Arial", 11))
label.pack()
fenetre.mainloop()
after() retourne un identifiant qu'on peut passer à after_cancel(id) pour annuler le callback avant son déclenchement — utile pour les tooltips ou les délais annulables.
Animation avec after() récursif
En appelant after() depuis le callback lui-même, on crée une boucle d'animation qui tourne dans la boucle principale sans bloquer :
import tkinter as tk
fenetre = tk.Tk()
fenetre.title("Horloge en temps réel")
fenetre.geometry("300x130")
from datetime import datetime
label_heure = tk.Label(fenetre, font=("Arial", 36, "bold"), fg="#1565c0")
label_heure.pack(expand=True)
job_id = [None]
def mettre_a_jour():
heure = datetime.now().strftime("%H:%M:%S")
label_heure.config(text=heure)
# Planifie le prochain appel dans 1 seconde
job_id[0] = fenetre.after(1000, mettre_a_jour)
def arreter():
if job_id[0]:
fenetre.after_cancel(job_id[0])
job_id[0] = None
mettre_a_jour()
fenetre.protocol("WM_DELETE_WINDOW", lambda: (arreter(), fenetre.destroy()))
fenetre.mainloop()
On stocke l'identifiant retourné par after() pour pouvoir annuler la boucle proprement à la fermeture. Sans ça, Tkinter peut lever une erreur si un callback est déclenché après la destruction de la fenêtre.
Threading pour les tâches longues
Pour les opérations qui prennent plusieurs secondes — téléchargement, lecture de gros fichiers, calcul intensif — threading est indispensable. La règle absolue : ne jamais modifier des widgets depuis un thread secondaire :
import tkinter as tk
from tkinter import ttk
import threading
import queue
import time
fenetre = tk.Tk()
fenetre.title("Thread + Queue")
fenetre.geometry("360x180")
file_msgs = queue.Queue() # canal de communication thread → interface
barre = ttk.Progressbar(fenetre, length=300, mode="determinate", maximum=100)
barre.pack(pady=20)
label = tk.Label(fenetre, text="Prêt")
label.pack()
def tache_longue():
for i in range(1, 11):
time.sleep(0.4) # simule un traitement
file_msgs.put(("progression", i*10)) # envoie un message à l'interface
file_msgs.put(("termine", None))
def verifier_queue():
try:
while True:
type_msg, valeur = file_msgs.get_nowait()
if type_msg == "progression":
barre["value"] = valeur
label.config(text=f"Traitement... {valeur} %")
elif type_msg == "termine":
label.config(text="Terminé !")
btn.config(state="normal")
except queue.Empty:
pass
fenetre.after(100, verifier_queue) # vérifie la queue toutes les 100 ms
def lancer():
btn.config(state="disabled")
barre["value"] = 0
t = threading.Thread(target=tache_longue, daemon=True)
t.start()
btn = tk.Button(fenetre, text="Lancer la tâche", command=lancer)
btn.pack(pady=5)
verifier_queue()
fenetre.mainloop()
Le schéma Queue est le pattern recommandé : le thread secondaire écrit dans la queue, la boucle principale lit la queue via after() régulier. La fenêtre reste réactive, et on ne touche jamais aux widgets depuis le thread. Le paramètre daemon=True garantit que le thread s'arrête automatiquement à la fermeture de l'application, sans qu'on ait besoin de l'arrêter manuellement. Ce mécanisme est particulièrement utile quand on charge des données avec Pandas ou qu'on effectue des calculs NumPy en arrière-plan.
Par carabde | Mis à jour le 30 avril 2025