Configuration des interfaces graphiques avec le gestionnaire pack de Tkinter

Introduction au gestionnaire pack

Le gestionnaire de disposition pack est l'un des outils les plus simples et les plus couramment utilisés dans Tkinter pour organiser les widgets. Il fonctionne sur le principe de l'empilement et de l'ajustement automatique des composants au sein de leur conteneur parent.

  1. Empilement vertical par défaut

Lorsqu'aucun paramètre spécifique n'est fourni, pack centre les widgets horizontalement et les empile verticalemant, du haut vers le bas.


import tkinter as tk

def center_window(window, w, h):
    screen_w = window.winfo_screenwidth()
    screen_h = window.winfo_screenheight()
    pos_x = (screen_w - w) // 2
    pos_y = (screen_h - h) // 2
    window.geometry(f"{w}x{h}+{pos_x}+{pos_y}")

if __name__ == "__main__":
    root = tk.Tk()
    root.title("Disposition par défaut")
    center_window(root, 300, 150)

    tk.Button(root, text="Premier", bg="coral").pack()
    tk.Button(root, text="Deuxième", bg="gold").pack()
    tk.Button(root, text="Troisième", bg="skyblue").pack()

    root.mainloop()

  1. Contrôle du remplissage et de l'expansion

Les paramètres fill et expand permettent de contrôler la manière dont un widget occupe l'espace disponible dans son conteneur.

2.1 Remplissage horizontal (fill=tk.X)

Le widget s'étire pour occuper toute la largeur disponible de son parent.


import tkinter as tk

def center_window(window, w, h):
    screen_w = window.winfo_screenwidth()
    screen_h = window.winfo_screenheight()
    pos_x = (screen_w - w) // 2
    pos_y = (screen_h - h) // 2
    window.geometry(f"{w}x{h}+{pos_x}+{pos_y}")

if __name__ == "__main__":
    app = tk.Tk()
    app.title("Remplissage Horizontal")
    center_window(app, 300, 150)

    tk.Button(app, text="Étendu en X", bg="lightgreen").pack(fill=tk.X)
    tk.Button(app, text="Normal", bg="lightyellow").pack()
    tk.Button(app, text="Normal", bg="lightblue").pack()

    app.mainloop()

2.2 Remplissage vertical (fill=tk.Y)

Pour étirer un widget verticalement, il faut souvent combiner fill=tk.Y avec un positionnement latéral via le paramètre side.


import tkinter as tk

def center_window(window, w, h):
    screen_w = window.winfo_screenwidth()
    screen_h = window.winfo_screenheight()
    pos_x = (screen_w - w) // 2
    pos_y = (screen_h - h) // 2
    window.geometry(f"{w}x{h}+{pos_x}+{pos_y}")

if __name__ == "__main__":
    app = tk.Tk()
    app.title("Remplissage Vertical")
    center_window(app, 300, 150)

    tk.Button(app, text="Étendu en Y", bg="lightcoral").pack(side=tk.LEFT, fill=tk.Y)
    tk.Button(app, text="Normal", bg="lightyellow").pack()
    tk.Button(app, text="Normal", bg="lightblue").pack()

    app.mainloop()

2.3 Expansion totale (fill=tk.BOTH, expand=True)

Pour qu'un widget occupe tout l'espace restant, tant en largeur qu'en hauteur, on utilise fill=tk.BOTH conjointement avec expand=True.


import tkinter as tk

def center_window(window, w, h):
    screen_w = window.winfo_screenwidth()
    screen_h = window.winfo_screenheight()
    pos_x = (screen_w - w) // 2
    pos_y = (screen_h - h) // 2
    window.geometry(f"{w}x{h}+{pos_x}+{pos_y}")

if __name__ == "__main__":
    app = tk.Tk()
    app.title("Expansion Totale")
    center_window(app, 300, 200)

    tk.Button(app, text="Occupe tout", bg="plum").pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
    tk.Button(app, text="Fixe", bg="lightyellow").pack()
    tk.Button(app, text="Fixe", bg="lightblue").pack()

    app.mainloop()

  1. Gestion des marges internes et externes

L'espacement autour et à l'intérieur des widgets est géré par les paramètres padx, pady (marges externes) et ipadx, ipady (marges internes).


import tkinter as tk

def center_window(window, w, h):
    screen_w = window.winfo_screenwidth()
    screen_h = window.winfo_screenheight()
    pos_x = (screen_w - w) // 2
    pos_y = (screen_h - h) // 2
    window.geometry(f"{w}x{h}+{pos_x}+{pos_y}")

if __name__ == "__main__":
    app = tk.Tk()
    app.title("Marges et Espacements")
    center_window(app, 300, 250)

    # ipadx/ipady agrandissent le widget lui-même, padx/pady ajoutent de l'espace autour
    tk.Button(app, text="Avec Marges", bg="salmon", width=15).pack(
        ipadx=15, ipady=10, padx=20, pady=15
    )
    tk.Button(app, text="Sans Marges", bg="lightgray", width=15).pack()

    app.mainloop()

Note : Le premier bouton apparaît visuellement plus grand grâce aux marges internes (ipadx, ipady), et l'espace vide qui le sépare du deuxième bouton provient des marges externes (padx, pady).

  1. Positionnement directionnel avec side

Le paramètre side permet d'ancrer les widgets sur les bords du conteneur parent (tk.TOP, tk.BOTTOM, tk.LEFT, tk.RIGHT).

4.1 Ancrage sur les quatre côtés


import tkinter as tk

def center_window(window, w, h):
    screen_w = window.winfo_screenwidth()
    screen_h = window.winfo_screenheight()
    pos_x = (screen_w - w) // 2
    pos_y = (screen_h - h) // 2
    window.geometry(f"{w}x{h}+{pos_x}+{pos_y}")

if __name__ == "__main__":
    app = tk.Tk()
    app.title("Ancrage Directionnel")
    center_window(app, 300, 200)

    tk.Button(app, text="Droite", bg="tomato").pack(side=tk.RIGHT)
    tk.Button(app, text="Gauche", bg="gold").pack(side=tk.LEFT)
    tk.Button(app, text="Bas", bg="dodgerblue").pack(side=tk.BOTTOM)
    tk.Button(app, text="Haut", bg="mediumseagreen").pack(side=tk.TOP)

    app.mainloop()

4.2 Empilement horizontal (de gauche à droite et inversement)

L'ordre d'appel de pack détermine l'ordre d'affichage des widgets lrosqu'ils partagent le même côté d'ancrage.


import tkinter as tk

def center_window(window, w, h):
    screen_w = window.winfo_screenwidth()
    screen_h = window.winfo_screenheight()
    pos_x = (screen_w - w) // 2
    pos_y = (screen_h - h) // 2
    window.geometry(f"{w}x{h}+{pos_x}+{pos_y}")

if __name__ == "__main__":
    app = tk.Tk()
    app.title("Empilement Horizontal")
    center_window(app, 400, 100)

    # Empilement de gauche à droite
    tk.Button(app, text="G1", bg="lightcoral").pack(side=tk.LEFT)
    tk.Button(app, text="G2", bg="lightyellow").pack(side=tk.LEFT)
    tk.Button(app, text="G3", bg="lightblue").pack(side=tk.LEFT)

    # Empilement de droite à gauche
    tk.Button(app, text="D1", bg="lightgreen").pack(side=tk.RIGHT)
    tk.Button(app, text="D2", bg="plum").pack(side=tk.RIGHT)
    tk.Button(app, text="D3", bg="peachpuff").pack(side=tk.RIGHT)

    app.mainloop()

4.3 Remplissage dynamique avec des conteneurs Frame

Pour créer des dispositions complexes, comme une grille de boutons qui s'adapte à la taille de la fenêtre, il est recommandé de combiner pack avec des conteneurs Frame.


import tkinter as tk

def center_window(window, w, h):
    screen_w = window.winfo_screenwidth()
    screen_h = window.winfo_screenheight()
    pos_x = (screen_w - w) // 2
    pos_y = (screen_h - h) // 2
    window.geometry(f"{w}x{h}+{pos_x}+{pos_y}")

if __name__ == "__main__":
    app = tk.Tk()
    app.title("Grille Dynamique")
    center_window(app, 400, 400)

    total_items = 16
    items_per_row = 4
    palette = ["red", "blue", "yellow", "pink", "green", "purple", "orange", "cyan"]
    color_idx = 0

    rows = total_items // items_per_row
    for _ in range(rows):
        row_frame = tk.Frame(app)
        row_frame.pack(fill=tk.BOTH, expand=True)
        
        for _ in range(items_per_row):
            btn = tk.Button(row_frame, text="Item", bg=palette[color_idx])
            btn.pack(side=tk.LEFT, expand=True, fill=tk.BOTH)
            color_idx = (color_idx + 1) % len(palette)

    app.mainloop()

Étiquettes: Tkinter Python GUI pack layout-manager

Publié le 4 juillet à 05h20