logo oujood
🔍

La barre de progression ttk Tkinter

Progressbar visualise l'avancement d'une tâche. Mode déterminé pour un avancement connu, mode indéterminé pour une attente de durée inconnue.

OUJOOD.COM

Le widget Progressbar appartient au module ttk et propose deux modes de fonctionnement : le mode déterminé, où la progression est connue et affichée sous forme de pourcentage, et le mode indéterminé, où la barre se déplace en boucle pour signaler qu'une tâche est en cours sans durée connue.

Mode déterminé

On fixe une valeur maximale et on incrémente la barre au fil de l'avancement :

📋 Copier le code

import tkinter as tk
from tkinter import ttk

fenetre = tk.Tk()
fenetre.title("Progressbar déterminée")
fenetre.geometry("360x160")

valeur = tk.DoubleVar()

barre = ttk.Progressbar(
    fenetre,
    orient=tk.HORIZONTAL,
    length=300,
    mode="determinate",
    variable=valeur,
    maximum=100
)
barre.pack(pady=25)

label_pct = tk.Label(fenetre, text="0 %")
label_pct.pack()

etape = [0]  # liste pour contourner la limitation des closures

def avancer():
    if etape[0] < 100:
        etape[0] += 10
        valeur.set(etape[0])
        label_pct.config(text=f"{etape[0]} %")
    if etape[0] >= 100:
        label_pct.config(text="Terminé !")
        btn.config(state="disabled")

btn = tk.Button(fenetre, text="Avancer (+10%)", command=avancer)
btn.pack()

fenetre.mainloop()

On lie la barre à une DoubleVar via variable — quand la variable change, la barre se met à jour automatiquement. On peut aussi appeler directement barre["value"] = 50 ou barre.step(10) pour incrémenter de 10 unités.

Mode indéterminé

Quand la durée d'une tâche n'est pas connue, le mode indeterminate anime la barre en boucle :

📋 Copier le code

import tkinter as tk
from tkinter import ttk

fenetre = tk.Tk()
fenetre.title("Progressbar indéterminée")
fenetre.geometry("340x160")

barre = ttk.Progressbar(
    fenetre,
    orient=tk.HORIZONTAL,
    length=280,
    mode="indeterminate"
)
barre.pack(pady=25)

label_etat = tk.Label(fenetre, text="En attente...")
label_etat.pack()

def demarrer():
    barre.start(15)   # intervalle en ms entre chaque pas
    label_etat.config(text="Chargement en cours...")
    btn_start.config(state="disabled")
    btn_stop.config(state="normal")

def arreter():
    barre.stop()
    label_etat.config(text="Arrêté.")
    btn_start.config(state="normal")
    btn_stop.config(state="disabled")

frame = tk.Frame(fenetre)
frame.pack()
btn_start = tk.Button(frame, text="Démarrer", command=demarrer)
btn_start.pack(side="left", padx=8)
btn_stop  = tk.Button(frame, text="Arrêter", command=arreter, state="disabled")
btn_stop.pack(side="left")

fenetre.mainloop()

start(interval) lance l'animation avec un pas toutes les interval millisecondes. stop() l'arrête et remet la barre à zéro. La valeur passée à start() contrôle la vitesse : un intervalle plus petit donne une animation plus rapide.

Progressbar avec after() — mise à jour depuis le thread principal

Tkinter n'est pas thread-safe — mettre à jour la barre depuis un thread secondaire provoque des comportements imprévisibles. La solution propre utilise after() pour programmer des mises à jour dans la boucle principale :

📋 Copier le code

import tkinter as tk
from tkinter import ttk

fenetre = tk.Tk()
fenetre.title("Progressbar avec after()")
fenetre.geometry("340x150")

barre = ttk.Progressbar(fenetre, length=280, mode="determinate", maximum=100)
barre.pack(pady=20)
label = tk.Label(fenetre, text="Prêt")
label.pack()

def simuler_tache(progression=0):
    if progression <= 100:
        barre["value"] = progression
        label.config(text=f"Traitement... {progression} %")
        # planifie la prochaine mise à jour dans 80 ms
        fenetre.after(80, simuler_tache, progression + 5)
    else:
        label.config(text="Terminé !")

tk.Button(fenetre, text="Lancer", command=lambda: simuler_tache(0)).pack()

fenetre.mainloop()

after(délai_ms, fonction, *args) planifie un appel dans la boucle d'événements principale après délai_ms millisecondes. La fenêtre reste réactive pendant toute la durée — l'utilisateur peut toujours interagir. Pour les vraies tâches longues en arrière-plan, la page sur after() et les threads couvre les cas plus avancés.

Par carabde | Mis à jour le 30 avril 2025