OUJOOD.COM
Quand une interface contient plus de trois ou quatre widgets, les placer tous directement dans la fenêtre principale devient difficile à maintenir. Le widget Frame résout ce problème : c'est une zone rectangulaire qui regroupe des widgets et peut elle-même être positionnée dans la fenêtre. Pensez-y comme à des calques dans une mise en page.
Créer un Frame simple
Un Frame se crée comme n'importe quel widget — en lui passant son parent en premier argument :
import tkinter as tk
fenetre = tk.Tk()
fenetre.title("Frame simple")
fenetre.geometry("400x250")
# Création d'un Frame avec bordure visible
cadre = tk.Frame(fenetre, bg="lightblue", bd=2, relief="groove")
cadre.pack(padx=20, pady=20, fill="both", expand=True)
# Les widgets suivants appartiennent au cadre, pas à la fenêtre
tk.Label(cadre, text="Je suis dans le Frame", bg="lightblue").pack(pady=10)
tk.Button(cadre, text="Bouton interne").pack()
fenetre.mainloop()
L'argument relief accepte plusieurs valeurs : "flat" (aucune bordure, défaut), "groove", "ridge", "sunken", "raised". C'est utile pour visualiser les zones lors du développement, même si on les retire souvent dans la version finale.
Diviser l'interface en zones
Le cas d'usage le plus courant : séparer l'interface en zones fonctionnelles — une barre du haut, une zone centrale, une barre du bas. Chaque zone est un Frame :
import tkinter as tk
fenetre = tk.Tk()
fenetre.title("Interface en zones")
fenetre.geometry("450x300")
# Zone haute — barre de titre ou menu
frame_haut = tk.Frame(fenetre, bg="#3c3f41", height=50)
frame_haut.pack(fill="x")
tk.Label(frame_haut, text="Barre supérieure", bg="#3c3f41", fg="white").pack(pady=12)
# Zone centrale — contenu principal
frame_centre = tk.Frame(fenetre, bg="#f5f5f5")
frame_centre.pack(fill="both", expand=True, padx=10, pady=10)
tk.Label(frame_centre, text="Zone de contenu", bg="#f5f5f5").pack(pady=30)
# Zone basse — boutons d'action
frame_bas = tk.Frame(fenetre, bg="#e0e0e0", height=45)
frame_bas.pack(fill="x")
tk.Button(frame_bas, text="Annuler").pack(side="right", padx=5, pady=8)
tk.Button(frame_bas, text="Valider").pack(side="right", padx=5, pady=8)
fenetre.mainloop()
Chaque Frame utilise pack() avec fill="x" pour occuper toute la largeur. Le frame_centre a expand=True en plus, ce qui lui permet de prendre tout l'espace vertical disponible quand la fenêtre est redimensionnée.
Frames imbriqués
Un Frame peut contenir d'autres Frame. C'est ce qui permet de construire des mises en page complexes sans que tout s'effondre dès qu'un widget change de taille :
import tkinter as tk
fenetre = tk.Tk()
fenetre.geometry("400x200")
# Frame parent
frame_principal = tk.Frame(fenetre, bg="#ddd")
frame_principal.pack(fill="both", expand=True, padx=10, pady=10)
# Deux colonnes à l'intérieur du frame principal
col_gauche = tk.Frame(frame_principal, bg="#c8e6c9", width=180)
col_gauche.pack(side="left", fill="both", expand=True, padx=(0, 5))
col_droite = tk.Frame(frame_principal, bg="#bbdefb", width=180)
col_droite.pack(side="left", fill="both", expand=True)
tk.Label(col_gauche, text="Colonne gauche", bg="#c8e6c9").pack(pady=20)
tk.Label(col_droite, text="Colonne droite", bg="#bbdefb").pack(pady=20)
fenetre.mainloop()
Ce type de structure en colonnes est la base de beaucoup d'interfaces réelles. Vous retrouverez ce schéma dans les exemples de la calculatrice et du gestionnaire de tâches en fin de cours.
Frame et gestionnaires de mise en page
Un point à ne pas oublier : dans un même Frame, vous ne pouvez pas mélanger pack() et grid(). Les deux gestionnaires sont incompatibles à l'intérieur d'un même conteneur. En revanche, un Frame peut utiliser grid() dans la fenêtre principale pendant que ses enfants utilisent pack() — les règles s'appliquent par conteneur, pas globalement. On approfondit ça dans les pages pack(), grid() et comment choisir entre eux.
Par carabde | Mis à jour le 30 avril 2025