NSI - Première - Projet_1: chiffrement d'un texte
Les interfaces graphiques avec Tkinter
Cliquez sur le lien du chapitre de cours à consulter:
- Tkinter
- Créer une fenêtre
- widget label : afficher du texte
- pack(): positionner les éléments simplement
- widget frame: créer des zones
- widget text: zone de texte
- widget Button (Bouton)
- grid(): positionner les éléments précisément
le package Tkinter
Tkinter (Tool kit interface) est la bibliothèque graphique standard et intégrée à Python. Cette bibliothèque vous permet de creér des interfaces graphiques: des fenêtres, des boites de dialogues, des boutons, des menus, etc..
Créer une fenêtre
Pour pouvoir créer une fenêtre, on doit commencer par importer le module tkinter ( avec t en lettre minuscule) pour ça on code:
import tkinterOn définit ensuite une variable (ici fen) qui représentera notre fenêtre et on lui assigne la valeur renvoyée par la fonction Tk() du module tkinter ( fonction qui renvoie un objet fenêtre):
fen = tkinter.Tk()
On écrit fen = tkinter.Tk() et pas fen = Tk() pour préciser que la fonction Tk() est dans le module tkinter
ASTUCE: beaucoup de codeurs donne un allias (autre nom) au module tkinter pour l'écrire plus vite, exemple :
import tkinter as tk
permet d'écrire tk à la place de tkinter:
fen = tk.Tk()
Voici le code minimal qui crée une fenêtre affichée en plein écran, les commentaires vous expliquent les lignes de code:
# importer module tkinter renommé tk
import tkinter as tk
# Créer objet fenêtre associé à variable fen
fen = tk.Tk()
# Ajouter le titre "projet chiffrer" à la fenêtre
fen.title("projet chiffrer")
# state("zoomed") = afficher en plein écran
fen.state("zoomed")
# Abonner la fenêtre aux événements (clic, etc..) détectés par l'OS
# l'OS sera Windows ou Linux en NSI
# tant que mainloop() n'agit pas on ne voit rien à l'écran
fen.mainloop()
Un objet possède des méthodes (des fonctions) pour le manipuler comme ici title(), state() et mainloop().
On applique une méthode à un objet avec le code:
nom_objet.nom_methode(arguments) par exemple ci-dessus: fen.title("projet chiffrer")
Si la méthode prend plusieurs arguments, on les sépare par une virgule:
nom_objet.nom_methode(argument1,argument2, etc..).
Exemple: la méthode resizable prend 2 arguments qui précisent si on autorise de redimensionner la fenêtre en largeur et en hauteur, si on interdit de redimensionner dans les deux directions, les deux arguments sont mis à False.
fen.resizable(False, False)
Voici quelques méthodes utiles de manipulation d'un objet fenêtre:
- Définir le titre de la fenêtre 'fen':
fen.title("Mon application")
- Fixer la taille de la fenêtre 'fen':
# largeur 800 pixels et hauteur 600 pixels
fen.geometry("800x600")
- Maximiser la fenêtre (avec Windows):
fen.state("zoomed")
Autres états possibles :
- "normal"
- "iconic" (réduite)
- "withdrawn" (cachée)
- Autoriser ou interdire le redimensionnement de fen
fen.resizable(True, False) # largeur oui, hauteur non
- Modifier les options de la fenêtre (couleur, bordure…):
# fond bleu
fen.config(bg="lightblue")
- Change l’icône de la fenêtre (Windows uniquement):
fen.iconbitmap("mon_icone.ico")
- Lance la boucle de gestion d'événements:
fen.mainloop()
Méthodes de placement et de gestion
- Force la mise à jour immédiate de l’interface graphique:
fen.update() - Exécute une fonction après un délai:
# on définit une fonction truc
def truc():
print("1 seconde")
# la méthode after exécute "truc" après 1000 ms = 1s
# truc() est une fonction de callback ( truc() est argument de after())
# on doit coder after(1000, truc) et pas after(1000, truc())
fen.after(1000, truc)
- Associer un événement clavier/souris:
# on va voir comment lier une fonction
# à un événement clavier ici 'appui sur la touche echap'
# On définit la fonction ferme(..)
# On veut que si ferme (..) est appelée la fenêtre disparaisse
# un objet fenêtre possède la méthode destroy() pour la détruire
# définition de ferme
# une fonction qui gère des événements possède l'argument event
def ferme(event):
# on appelle destroy pour la fenêtre fen
fen.destroy()
# la méthode bind associe un évènement à une fonction
# on lie la fonction ferme à l'évènement <Escape>
# <Escape> correspond à 'appui sur touche echap'
# ferme() est fonction de callback de bind() ( ferme() est argument de bind())
# on doit coder bind("<Escape>", ferme) et pas bind("<Escape>", ferme(..))
fen.bind("<Escape>", ferme )
Il existe beaucoup d'événements clavier, voici quelques mots clés:
Alt_L : touche Alt à gauche du clavier.
Alt_R : touche Alt à droite du clavier.
BackSpace : touche retour arrière (backspace).
Cancel : touche annulation (sur certains systèmes uniquement).
Caps_Lock : touche verrouillage du clavier en majuscules.
Down : touche flèche vers le bas.
Escape : touche d'échappement (Ech).
Left: touche Flèche recule (vers la gauche).
Return : touche entrée (return).
Right : touche flèche avance (vers la droite).
Up : touche flèche vers le haut.
- Renvoie la taille actuelle de la fenêtre largeur et hauteur:
print(fen.winfo_width(), fen.winfo_height())
- Renvoie la position de la fenêtre:
print(fen.winfo_x(), fen.winfo_y())
Exemple de code qui reprend quelques points décrits au dessus:
import tkinter as tk
fen = tk.Tk()
fen.title("Exemple")
fen.geometry("800x600")
fen.state("zoomed")
fen.config(bg="lightgray")
fen.resizable(True, False)
fen.minsize(600, 400)
# quitter va être associée à l'événement Escape
def quitter(event):
print("Au revoir")
fen.destroy()
# on lie la fonction quitter avec l'événement Escape
fen.bind("<Escape>", quitter)
fen.mainloop()
Le widget Label
un widget est un élément graphique que l'on peut mettre dans une fenêtre; par exemple les boutons, les menus déroulants, les zones saisies, etc..., sont des widgets.
Un label est un widget qui permet d'afficher une texte dans la fenêtre. Dans la fenêtre ci-dessous les textes "Texte Original" et "Texte chiffré" sont des Labels:
Voici un code qui crée deux labels et ne cherche pas à les positionner précisément pour l'instant:
# importer module tkinter renommé tk
import tkinter as tk
# Créer objet fenêtre associé à variable fen
fen = tk.Tk()
# Ajouter le titre "projet chiffrer" à la fenêtre
fen.title("projet chiffrer")
# state("zoomed") = afficher en plein écran
fen.state("zoomed")
# voici le code de création d'un label jaune:
label_gauche = tk.Label(fen, bg="lightyellow",
text="Texte original", font=("Arial", 12))
# positionnement simple côté gauche
# on ne cherche pas à positionner précisément
label_gauche.pack(side="left")
# voici le code de création d'un label bleu:
label_droit = tk.Label(fen, bg="lightblue",
text="Texte chiffré", font=("Arial", 12))
# positionnement à gauche mais 50 px à droite du précédent widget
# padx règle une marge horizontale
label_droit.pack(side="left", padx=50)
# Abonner la fenêtre aux événements (clic, etc..) de Windows
# tant que mainloop() n'agit pas on ne voit rien à l'écran
fen.mainloop()
Affichage:
Dans le code ci-dessus, les deux labels sont positionnés avec la méthode pack() qui permet de positionner les widgets les uns au dessus des autres ou les uns à côté des autres. Ici on a choisi les uns à côté des autres par rapport au bord gauche (side="left"), on peut séparer les widget avec une marge horizontale ( padx). Dans la partie positionnement vous verrez comment obtenir un positionnement plus précis. Pour l'instant on se contente de faire apparaitre le widget et d'appliquer des marges.
Positionnement avec pack()
La méthode pack() permet de positionner les widgets les uns au dessus des autres ou les uns à côté des autres, ce critère d'empilement est défini avec l'argument side :
- Les uns au dessus des autres et de haut vers bas si side = "top" ou de bas vers haut si side="bottom".
- Les uns à côté des autres et de gauche à droite si side ="left" ou de droite à gauche si side="right"
La méthode pack() prend aussi des arguments qui précisent comment occuper l'espace autour du widget:
-
L'argument expand="True" permet à un widget qui n'a pas de taille prédéfinie de demander l'accès à de l'espace non occupé de son conteneur. Ce paramètre est notamment nécessaire pour des widgets conteneurs qui ont une taille qui est définie par ce qu'ils contiennent ( ils n'ont pas eux même de taille propre) comme les frames ( voir le chapitre dédié aux frames )
-
L'argument fill permet d'étendre le widget dans la direction perpendiculaire à side ( fill="x": étendre horizontalement, fill="y": étendre verticalement, fill="both": : étendre dans toutes les directions). Si le widget n'a pas de taille défini il faudra préciser expand="True" avant de demander l'extension.
La méthode pack() permet un positionnement simple mais pas très précis. On lui préfèrera souvent la méthode grid() qui fait l'objet d'un autre chapitre de ce cours.
Voici un code qui permet de positionner 4 widgets par rapport aux 4 bords de la fenêtre (side = "top", side ="left", side="right" et side="bottom" ) avec des marges horizontales (padx) et verticales (pady)
# importer module tkinter renommé tk
import tkinter as tk
# Créer objet fenêtre associé à variable fen
fen = tk.Tk()
# Ajouter un titre à la fenêtre
fen.title("projet chiffrer")
# state("zoomed") = afficher en plein écran
fen.state("zoomed")
# voici le code de création d'un label jaune:
label_gauche = tk.Label(fen, bg="lightyellow",
text="label gauche", font=("Arial", 12))
# positionnement par rapport au côté gauche
# marge horizontale de 50 px à gauche pas à droite padx=(50,0)
label_gauche.pack(side='left', padx=(50,0))
# positionnement par rapport au côté droit
# voici le code de création d'un label bleu:
label_droit = tk.Label(fen, bg="lightblue",
text="label droit", font=("Arial", 12))
# marge horizontale de 50 px
label_droit.pack(side="right", padx=50)
# voici le code de création d'un label corail:
label_haut = tk.Label(fen, bg="lightcoral",
text="label haut", font=("Arial", 12))
# positionnement par rapport au sommet
# marge verticale de 50 px
label_haut.pack(side='top', pady=50)
# voici le code de création d'un label orange:
label_bas = tk.Label(fen, bg="orange",
text="label bas", font=("Arial", 12))
# positionnement par rapport au bas
# marge verticale de 50 px
label_bas.pack(side='bottom', pady=50)
# Abonner la fenêtre aux événements (clic, etc..) de Windows
# tant que mainloop() n'agit pas on ne voit rien à l'écran
fen.mainloop()
Les labels sont placés dans les bords, mais ils n'occupent pas tout l'espace. On peut changer ça en utilisant le paramètre fill : il prend les valeurs "x" (occupe tout l'espace horizontal), "y" (occupe tout l'espace vertical)et "both" (occupe tout l'espace horizontal et vertical). ci-dessous on a ajouté fill aux labels pour occuper tout l'espace de chaque bords.
# importer module tkinter renommé tk
import tkinter as tk
# Créer objet fenêtre associé à variable fen
fen = tk.Tk()
# Ajouter un titre à la fenêtre
fen.title("projet chiffrer")
# state("zoomed") = afficher en plein écran
fen.state("zoomed")
# voici le code de création d'un label jaune:
label_gauche = tk.Label(fen, bg="lightyellow",
text="label gauche", font=("Arial", 12))
# positionnement par rapport au côté gauche
# marge horizontale de 50 px à gauche pas à droite padx=(50,0)
# occupe tout l'espace vertical fill='y'
label_gauche.pack(side='left', fill='y', padx=(50,0))
# positionnement par rapport au côté droit
# voici le code de création d'un label bleu:
label_droit = tk.Label(fen, bg="lightblue",
text="label droit", font=("Arial", 12))
# marge horizontale de 50 px et occupe tout l'espace vertical
label_droit.pack(side="right", fill='y', padx=50)
# voici le code de création d'un label corail:
label_haut = tk.Label(fen, bg="lightcoral",
text="label haut", font=("Arial", 12))
# positionnement par rapport au sommet
# marge verticale de 50 px et occupe tout l'espace horizontal
label_haut.pack(side='top', fill="x", pady=50)
# voici le code de création d'un label orange:
label_bas = tk.Label(fen, bg="orange",
text="label bas", font=("Arial", 12))
# positionnement par rapport au bas
# marge verticale de 50 px et occupe tout l'espace horizontal
label_bas.pack(side='bottom', fill="x", pady=50)
# Abonner la fenêtre aux événements (clic, etc..) de Windows
# tant que mainloop() n'agit pas on ne voit rien à l'écran
fen.mainloop()
L'ordre de définition des widgets dans le code à son importance dans le rendu, si un widget s'étend il empêche un autre de prendre cette place. Dans le code ci-dessous, on place deux labels avec side="top" mais le second label est déclaré après les widgets gauche et droit, une partie de l'espace horizontal est déjà occupé par le label gauche et le label droit, il ne peut s'étendre horizontalement que jusqu'à ces deux labels.
# importer module tkinter renommé tk
import tkinter as tk
# Créer objet fenêtre associé à variable fen
fen = tk.Tk()
# Ajouter un titre à la fenêtre
fen.title("projet chiffrer")
# state("zoomed") = afficher en plein écran
fen.state("zoomed")
# voici le code de création d'un label corail:
label_haut = tk.Label(fen, bg="lightcoral",
text="label haut", font=("Arial", 12))
# positionnement par rapport au sommet
# occupe tout l'espace horizontal
label_haut.pack(side='top', fill="x")
# voici le code de création d'un label jaune:
label_gauche = tk.Label(fen, bg="lightyellow",
text="label gauche", font=("Arial", 12))
# positionnement par rapport au côté gauche
# occupe tout l'espace vertical fill='y'
label_gauche.pack(side='left', fill='y')
# positionnement par rapport au côté droit
# voici le code de création d'un label bleu:
label_droit = tk.Label(fen, bg="lightblue",
text="label droit", font=("Arial", 12))
# occupe tout l'espace vertical
label_droit.pack(side="right", fill='y')
# voici le code de création d'un label jaune:
label_haut_2 = tk.Label(fen, bg="lightyellow",
text="label haut2", font=("Arial", 12))
# positionnement par rapport au sommet
# occupe tout l'espace horizontal
label_haut_2.pack(side='top', fill="x")
# voici le code de création d'un label orange:
label_bas = tk.Label(fen, bg="orange",
text="label bas", font=("Arial", 12))
# positionnement par rapport au bas
# occupe tout l'espace horizontal
label_bas.pack(side='bottom', fill="x")
# Abonner la fenêtre aux événements (clic, etc..) de Windows
# tant que mainloop() n'agit pas on ne voit rien à l'écran
fen.mainloop()
Ajoutons un 5eme label centré, on peut utilisé pour ça expand=True ou "Expand = 1", pack() répartit l'espace de manière équilibrée, expand veut dire "si de l’espace libre existe dans le conteneur, je veux une part de cet espace", si un seul widget a ce paramètre et n'a pas de fill, il flottera au centre.
# importer module tkinter renommé tk
import tkinter as tk
# Créer objet fenêtre associé à variable fen
fen = tk.Tk()
# Ajouter un titre à la fenêtre
fen.title("projet chiffrer")
# state("zoomed") = afficher en plein écran
fen.state("zoomed")
# voici le code de création d'un label corail:
label_haut = tk.Label(fen, bg="lightcoral",
text="label haut", font=("Arial", 12))
# positionnement par rapport au sommet
# occupe tout l'espace horizontal
label_haut.pack(side='top', fill="x")
# voici le code de création d'un label jaune:
label_gauche = tk.Label(fen, bg="lightyellow",
text="label gauche", font=("Arial", 12))
# positionnement par rapport au côté gauche
# occupe tout l'espace vertical fill='y'
label_gauche.pack(side='left', fill='y')
# positionnement par rapport au côté droit
# voici le code de création d'un label bleu:
label_droit = tk.Label(fen, bg="lightblue",
text="label droit", font=("Arial", 12))
# occupe tout l'espace vertical
label_droit.pack(side="right", fill='y')
# voici le code de création d'un label jaune:
label_haut_2 = tk.Label(fen, bg="lightyellow",
text="label haut2", font=("Arial", 12))
# positionnement par rapport au sommet
# occupe tout l'espace horizontal
label_haut_2.pack(side='top', fill="x")
# voici le code de création d'un label orange:
label_bas = tk.Label(fen, bg="orange",
text="label bas", font=("Arial", 12))
# positionnement par rapport au bas
# occupe tout l'espace horizontal
label_bas.pack(side='bottom', fill="x")
# voici le code de création d'un label bleu:
label_centre = tk.Label(fen, bg="blue",
text="label centre", font=("Arial", 12))
# positionnement au centre
label_centre.pack( expand="1")
# Abonner la fenêtre aux événements (clic, etc..) de Windows
# tant que mainloop() n'agit pas on ne voit rien à l'écran
fen.mainloop()
Si on veut que le label occupe tout l'espace central, on lui affecte le paramètre fill= "both"
# positionnement au centre
label_centre.pack( expand="1", fill= "both" )
widget frame: créer des zones
Un widget frame est une zone qui peut accueillir d'autres widgets, on peut s'en servir pour répartir les widgets selon un agencement particulier.
Ci-dessous vous avez trois frames colorés (vert, bleu et rouge ), le bleu contiennt des widgets boutons:Affichage:
L'utilisation de frame n'est pas si simple lorsqu'il s'agit de les positionner avec pack().
On doit agir sur :
- side qui fixe la direction d’empilement
- fill qui étire dans la direction perpendiculaire à side mais fill n’agit que s’il reste de l’espace libre.
- expand demande de l’espace libre dans le conteneur.
Exemple de code:
import tkinter as tk
fen = tk.Tk()
fen.title("Frame")
# --- Cadre gauche ---
frame_gauche = tk.Frame(fen, bg="lightgreen")
frame_gauche.pack(side="left", fill="both", expand="True", padx=20, pady=20)
# --- Cadre droit ---
frame_droit = tk.Frame(fen, bg="lightcoral")
frame_droit.pack(side="right", fill="both", expand="True", padx=20, pady=20)
# --- cadre bas ---
frame_bas = tk.Frame(fen, bg="lightblue")
frame_bas.pack(side="bottom", fill="both", expand="True", pady=20)
fen.mainloop()
Dans le code ci-dessus, on cherche à positionner trois frames deux en haut à gauche (vert) et à droite (rouge) et un en bas (bleu). Au départ les frames ne contiennent pas de widgets.
Les deux frames en haut demandent de l'espace libre avec expand = "True" et de remplir cet espace dans toutes les directions avec fill="both". Le frame bleu en bas n'a plus d'espace pour exister, on ne voit qu'un trait bleu vertical.
Affichage:
On rajoute maintenant des widgets boutons dans le frame bleu:
import tkinter as tk
fen = tk.Tk()
fen.title("Frame")
# --- Cadre gauche ---
frame_gauche = tk.Frame(fen, bg="lightgreen")
frame_gauche.pack(side="left", fill="both", expand="True", padx=20, pady=20)
# --- Cadre droit ---
frame_droit = tk.Frame(fen, bg="lightcoral")
frame_droit.pack(side="right", fill="both", expand="True", padx=20, pady=20)
# --- cadre bas ---
frame_bas = tk.Frame(fen, bg="lightblue")
frame_bas.pack(side="bottom", fill="both", expand="True", pady=20)
tk.Button(frame_bas, text="Enregistrer", command=enregistrer).pack(side="bottom",pady=10, padx=10)
tk.Button(frame_bas, text="Ouvrir", command=ouvrir).pack(side="bottom", pady=10, padx=10)
fen.mainloop()
Affichage: le frame bleu apparait mais il n'est pas en bas malgré de side="bottom"!
Avec pack(), la solution est de mettre les frames haut gauche et haut droit dans un frame haut placé avec side="top" qui revendique l'espace libre expand="True" et de s'étendre dans toutes les directions fill="both". Le frame bas est lui placé avec side="bottom", il revendique également l'espace libre avec expand="True" et de s'étendre dans toutes les directions fill="both". La méthode pack() donnera à frame haut et frame bas la moitié de la fenêtre.
Le code ci-dessous ajoute des widgets (label et bouton) dans chacun des frames car c'est le but ( un frame est une zone pour contenir des widgets ).
import tkinter as tk
fen = tk.Tk()
fen.title("Frame")
# --- principal ---
# frame_conteneur est placé dans fen
frame_conteneur = tk.Frame(fen)
frame_conteneur.pack(side="top", fill="both", expand="True")
# --- Cadre gauche ---
# frame_gauche est placé dans frame_conteneur
frame_gauche = tk.Frame(frame_conteneur, bg="lightgreen")
frame_gauche.pack(side="left", fill="both", expand="True", padx=20, pady=20)
# deux labels sont placés dans frame_gauche
tk.Label(frame_gauche, bg="yellow", text="gauche").pack(anchor="w", pady=20)
tk.Label(frame_gauche, bg="lightblue", text="gauche2").pack(anchor="w", padx=20)
# --- Cadre droit ---
# frame_droit est placé dans frame_conteneur
frame_droit = tk.Frame(frame_conteneur, bg="lightcoral")
frame_droit.pack(side="right", fill="both", expand="True", padx=20, pady=20)
# deux labels sont placés dans frame_droit
tk.Label(frame_droit, bg="white", text="Droit").pack(anchor="e", padx=20, pady=20)
tk.Label(frame_droit, bg="yellow", text="Droit2").pack(anchor="w", padx=20)
# --- cadre bas ---
# frame_bas est placé dans fen
frame_bas = tk.Frame(fen, bg="lightblue")
frame_bas.pack(side="bottom", fill="both", expand="True", pady=20)
# deux boutons sont placés dans frame_bas
tk.Button(frame_bas, text="Enregistrer").pack(side="bottom",pady=10, padx=10)
tk.Button(frame_bas, text="Ouvrir").pack(side="bottom", pady=10, padx=10)
# ON AFFICHE LA FENÊTRE A LA FIN
fen.mainloop()
Affichage:
widget Text: zone de texte
Un widget Text permet de saisir des textes et d'en afficher, c'est une zone de saisie et d'affichage de texte. Dans l'image ci-dessous vous avez deux zones de saisie de texte (widget Text) avec fond blanc:
Voici comment coder une zone de texte:
import tkinter as tk
fen = tk.Tk()
# on définit la variable zone_texte qui la représente
# On assigne la variable à la fonction tk.Text()
# on définit les arguments de Text():
# placé dans la fenêtre fen
# taille de la zone de texte width=40, height=10,
# fond de la zone blanc bg="white"
# couleur texte saisi noir fg="black"
# Police texte "Segoe UI" taille 12
# coupe les lignes entre les mots: wrap="word"
zone_texte = tk.Text(
fen,
width=40,
height=10,
bg="white",
fg="black",
font=("Segoe UI", 12),
wrap="word")
# positionner avec marges de 10px
zone_texte.pack(padx=10, pady=10)
# affichage fenêtre
fen.mainloop()
Affichage:
Quelques réglages de wrap:
Comportement:
- wrap="word" # coupe les lignes entre les mots (pas au milieu du mot)
- wrap="char" # coupe au caractère
- wrap="none" # pas de retour à la ligne automatique
Voici quelques méthodes de manipulation des zones de texte:
- Insérer du texte avec du code python:
# à la fin
zone_texte.insert("end", "Bonjour moi\n")
# au début "1.0"
zone_texte.insert("1.0", "Début du texte\n")
- Récupérer le contenu de la zone:
# "end-1c" : enlève le saut de ligne à la fin du texte
contenu = zone_texte.get("1.0", "end-1c")
# "end" : garde le saut de ligne à la fin du texte
contenu = zone_texte.get("1.0", "end")
- Effacer le contenu de la zone:
zone_texte.delete("1.0", "end")
- Ajouter des barres de défilement:
scroll = tk.Scrollbar(fen, command=zone_texte.yview)
zone_texte.configure(yscrollcommand=scroll.set)
scroll.pack(side="right", fill="y")
zone_texte.pack(side="left", fill="both", expand=True)
zone_texte.config(state="disabled")
import tkinter as tk
fen = tk.Tk()
zone_texte = tk.Text(fen, width=40, height=10, wrap="word",
bg="#f9f9f9", font=("Segoe UI", 12),
relief="sunken", borderwidth=2)
zone_texte.pack(side="left", fill="both", expand=True)
scroll = tk.Scrollbar(fen, command=zone_texte.yview)
scroll.pack(side="right", fill="y")
zone_texte.config(yscrollcommand=scroll.set)
zone_texte.insert("end", "Bonjour Toi !\nVoici un widget Text.\n")
fen.mainloop()
Affichage:
le widget Button
Un widget Button permet d'associer une fonction à un bouton, la fonction s'exécute lorsque l'on clique sur le bouton.
- le premier est la fenêtre ou conteneur du bouton.
- le second est l'argument text qui est assigné au texte à afficher dans le bouton, par exemple: text="Chiffrer".
Affichage:
- le troisième est l'argument command qui est assigné à la fonction à exécuter si on clique sur le bouton, par exemple: command="chiffre", si on clique sur le bouton, le programme exécute la fonction chiffre().
Voici le code qui crée un bouton et l'associe à la fonction chiffrer()
import tkinter as tk
# la fonction à exécuter
def chiffre():
# à compléter
pass
fen = tk.Tk()
# Une zone de texte en haut
zone_texte = tk.Text(fen, width=40, height=10, wrap="word",
bg="#f9f9f9", font=("Segoe UI", 12),
relief="sunken", borderwidth=2)
zone_texte.pack(side="top", fill="x", , padx="10")
# le bouton en bas de la fenêtre
bouton = tk.Button(fen, text="Chiffrer", command="chiffre")
bouton.pack(side="bottom", pady="10")
fen.mainloop()
grid: positionner les éléments précisément
La méthode grid() permet de positionner les widgets dans une grille configurable. Les éléments sont placés dans des cellules numérotées de la grille: row = 0 et column = 0 est la cellule de ligne (row) = 0 et de colonne (column) = 0 (la cellule en haut à gauche de la grille)
La fenêtre peut posséder une grille et les widgets conteneurs placés dans cette fenêtre peuvent avoir leur propre grille ce qui permet un positonnement très précis.
Voici un exemple de grille pour positionner des widgets:
Affichage:
Si vous analyser le dessin la fenêtre (en rouge) possède une grille avec deux lignes (row=0 et row=1) et deux colonnes ((column=0 et column=1)).
La ligne 0 fait 2/3 de la hauteur de la fenêtre ce qui se règle avec l'argument weight de la méthode grid_rowconfigure.
-
La méthode grid_rowconfigure prend deux arguments: le premier est le numéro de ligne et le second est le poids donné à cette ligne. Le poids à 3 valeurs possibles:
weight = 0 : la ligne ne s'agrandit pas (elle a la taille de la hauteur des widgets qu'elle contient )
weight = 1 : la ligne peut s'agrandir proportionnement, si deux lignes ont weight=1 elles s’agrandissent de manière égale (ça permet d'avoir deux lignes de même hauteur par exemple).
weight = 2: la ligne reçoit deux fois plus d’espace qu’une ligne à weight=1 (ça permet d'avoir une ligne 2/3 plus haute qu'une autre ) -
La méthode grid_columnconfigure fonctionne de la même façon pour les colonnes.
Voici le code avec grille de la fenêtre rouge ci-dessus:
import tkinter as tk
fenetre = tk.Tk()
fenetre.title("Tutoriel grid")
fenetre.state("zoomed")
# --- Configuration de la grille de la fenêtre ---
# ligne 0 possède 2/3 hauteur de la hauteur fenetre
# réglé avec weight=2
fenetre.grid_rowconfigure(0, weight=2)
# ligne 1 possède 1/3 hauteur de la hauteur fenetre
# réglé avec weight=1
fenetre.grid_rowconfigure(1, weight=1)
# colonnes 0 et 1 possède la même largeur
# réglé avec weight=1
fenetre.grid_columnconfigure(0, weight=1)
fenetre.grid_columnconfigure(1, weight=1)
Pour positionner un widget comme frame_gauche dans la grille de la fenêtre avec grid() ou un des widgets label et zone de texte dans la grille de frame_gauche, on doit fournir la valeur de 3 arguments:
- la ligne row où mettre le widget.
- la colonne column où mettre le widget.
- comment il s'étire dans la cellule avec sticky:
Les directions de positionnement possibles sont:
• n = nord (haut)
• s = sud (bas)
• e = est (droite)
• w = ouest (gauche)
Règle d’or
• sticky="" → le widget reste au centre de sa cellule
• sticky="ew" → le widget s’étire horizontalement
• sticky="ns" → le widget s’étire verticalement
• sticky="nsew" → le widget s’étire dans toute la cellule
Si on veut que frame_gauche soit dans la première cellule de la fenêtre et occupe toute la cellule, on codera:
frame_gauche = tk.Frame(fenetre)
frame_gauche.grid(row=0, column=0, sticky="nsew").
Voici maintenant le code qui permet à frame_gauche de possèder sa propre grille, il contient dans sa cellule(0,0) un label appelé label_gauche centré sticky="" dans la cellule et dans sa cellule(0,1) une zone de texte appelé zone_texte_gauche qui occupe toute la cellule:
# --- création de Frame en haut gauche de fenetre ---
frame_gauche = tk.Frame(fenetre, bg="lightgreen")
# frame_gauche positionné en ligne 0 et colonne 0
frame_gauche.grid(row=0, column=0, sticky="nsew")
# frame_gauche possède deux lignes 0 et 1
# ligne 0 garde sa hauteur minimale (weight=0)
# ainsi l'élément placé dedans ne s'étirera pas
frame_gauche.grid_rowconfigure(0, weight=0)
# ligne 1 s'adapte à l'espace (weight=1)
# ainsi l'élément placé dedans s'étirera
frame_gauche.grid_rowconfigure(1, weight=1)
# la colonne 0 s'adapte à l'espace (weight=1)
# ainsi l'élément placé dedans s'étirera
frame_gauche.grid_columnconfigure(0, weight=1)
# positionnement du label en ligne 0 colonne 0 de frame_gauche
# le label affiche Texte original en taille 16
label_gauche = tk.Label(frame_gauche, bg="yellow",
text="label", font=("Arial", 16))
label_gauche.grid(row=0, column=0, sticky="")
# positionnement de la zone de texte en ligne 1 colonne 0 de frame_gauche
# l'élément est étiré dans toutes les directions sticky="nsew"
zone_texte_gauche = tk.Text(frame_gauche)
zone_texte_gauche.grid(row=1, column=0, sticky="nsew")
Sur le dessin ci-dessus, dans les cellules (1,0) et (1,1) de la fenêtre, on a positionné un frame appelé frame_bas, ce frame occupe deux colonnes ce qui se règle avec l'argument columnspan=2 de grid(); frame_bas possède sa propre grille ( de 3 lignes et 2 colonnes ). La ligne 1 contient deux widgets boutons et elle n'occupe en hauteur que la place des boutons ( weight = 0 ), les lignes 0 et 2 s'étendent proportionnellement ( weight = 1 ) ce qui leur permet d'occuper l'espace libre de frame_bas. Les boutons sont donc au centre de frame_bas.
Voici le code correspondant:
# --- Frame bas ---
frame_bas = tk.Frame(fenetre)
frame_bas.grid(row=1, column=0, columnspan=2, sticky="nsew")
# frame bas grille de 3 lignes
frame_bas.grid_rowconfigure(0, weight=1)
frame_bas.grid_rowconfigure(1, weight=0)
frame_bas.grid_rowconfigure(2, weight=1)
# frame bas grille de 2 colonnes
frame_bas.grid_columnconfigure(0, weight=1)
frame_bas.grid_columnconfigure(1, weight=1)
# bouton chiffrer
btn_chiffrer = tk.Button(frame_bas, text="Chiffrer", font=("Arial", 14))
# les attributs ipadx, ipady augmente la taille du bouton
btn_chiffrer.grid(row=1, column=0, sticky="n", ipadx=5, ipady=5)
# bouton déchiffrer
btn_dechiffrer = tk.Button(frame_bas, text="Déchiffrer", font=("Arial", 14))
btn_dechiffrer.grid(row=1, column=1, sticky="n", ipadx=5, ipady=5)