python tkinter

Identification

Infoforall

Fiche Tkinter pour Python


Fiche qui précise comment créer des fenêtre basiques avec la bibliothèque tkinter.

D'autres fiches tkinter permettront de détailler d'autres aspects.

Ici, on part à l'essentiel pour réaliser une application comportant des zones qu'on peut colorer, sur lesquelles on peut écrire et cliquer pour provoquer des effets.

Les notions vues ici :

  1. Partie 1 : Créer la fenêtre
    • Constructeur Tk
    • Méthode geometry
    • Méthode title
    • Méthode configure pour modifier après création
    • Méthode mainloop pour lancer la surveillance des événements
  2. Partie 2 : Créer, modifier et lire les attributs des widgets
    • Constructeur Label pour créer un widget Texte
    • Méthode pack pour afficher et placer simplement le widget
    • Méthode place pour afficher et placer à des coordonnées précises
    • Méthode configure pour modifier après création
    • Méthode cget pour récupérer la valeur d'un attribut
  3. Partie 3 : Utiliser le gestionnaire d'événements
    • Méthode bind pour utiliser le gestionnaire d'événements
    • Description des différents événements
    • Fonction événementielle et paramètre event pour récupérer les informations de l'événement
  4. Partie 4 : Placer précisement les widgets
    • Méthode place pour afficher et placer le widget à des coordonnées précises
  5. Partie 5 : Animer automatiquement
    • Méthode after pour programmer un appel retardé à une fonction
  6. Partie 6 : Utilisation avancée
    • Fonction lambda pour envoyer l'adresse d'une fonction créée à la volée (hors programme, à n'utiliser que dans le cadre des interfaces graphiques)

1 - Créer une fenêtre pour l'application

tkinter est le nom d'une des bibliothèques qui permet de réaliser des interfaces graphiques. Il ne s'agit pas de la plus performante, de la plus jolie mais elle a l'intêret d'être assez présente sur le Web. On peut ainsi trouver beaucoup d'exemples assez facilement. Et de ne pas être trop complexe à prendre en main pour réaliser de petites applications non profesionnelles.

Le module est installé de base avec les versions Python disponibles sous Windows.

Voici un code basique permettant de créer une fenêtre graphique :

1 2 3 4 5 6 7 8 9 10 11 12
import tkinter as tk # Création de la fenêtre du logiciel fenetre = tk.Tk() # Configuration de la fenêtre fenetre.geometry("600x300") fenetre.title("Ma super application") fenetre.configure(bg="black") # Surveillance des événements fenetre.mainloop()
  • Ligne 1 : Importation du module et création de l'alias tk.
  • Ligne 4 : Création d'un objet-fenêtre nommé fenetre à partir de la classe Tk.
  • Ligne 7 : Choix des dimensions de la fenêtre avec la méthode geometry à qui on fournit les dimensions sous forme d'un string : largeur (600 pixels) puis hauteur (300 pixels).
  • Ligne 8 : Choix du titre de la fenêtre avec la méthode title, visible dans la barre supérieure
  • Ligne 9 : Modification du fond coloré avec la méthode configure (bg pour background). On donne la couleur sous forme d'un string. On peut donner une couleur prédéfinie ou la choisir en utilisant les trois intensités RGB sous forme hexadécimale #RRGGBB. Les intensités hexadécimales varient entre
    • 00 (la plus faible) et
    • FF (la plus forte)
    • Exemples
    • # rouge fenetre.configure(bg="#FF0000") # rouge foncé fenetre.configure(bg="#880000") # jaune fenetre.configure(bg="#FFFF00")
  • Ligne 12 : la méthode mainloop permet de lancer la surveillance des événements. Loop signifie bouclage, et main signifie principal. S'agissant d'une interface graphique, le principe est de passer en programmation événementielle et donc de surveiller les événements : clicks sur l'écran, touches claviers activées ...
  • La dernière ligne de votre application graphique sera donc toujours fenetre.mainloop() ou équivalent.

2 - Création du Widget Label (pour le texte)

Le mot widget est la contraction de window et de gadget.

Trois parties :

  1. Création et configuration
  2. Modification après création
  3. Lecture du contenu

Voici le code que nous allons analyser :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
import tkinter as tk # Création de la fenêtre du logiciel fenetre = tk.Tk() # Configuration de la fenêtre fenetre.geometry("600x300") fenetre.title("Ma super application") fenetre.configure(bg="black") # Création-configuration d'un Label et affichage monLabel = tk.Label(fenetre, text = "Bonjour", fg="white", bg="#884400", width=10, height=5) monLabel.pack() # Surveillance des événements fenetre.mainloop()

2.1 - Création

Les widgets sont des objets et sont donc créés en utilisant un constructeur nommé Label.

12
monLabel = tk.Label(fenetre, ... plein d'autres arguments envoyés)

Le premier paramètre à fournir est la référence d'un objet de type Tk. Ici, je donne donc fenetre, le nom de la variable contenant la référence de la fenêtre dans le code précédent. Exemple (cette ligne seule ne suffit pas attention ):

12
monLabel = tk.Label(fenetre, text="Bonjour", fg="white", bg="#884400", width=10, height=5)

Les autres paramètres nommés possibles sont :

  •  text="Bonjour"  permet de fournir le texte qu'on veut voir s'afficher dans le widget.
  •  fg="white"  permet de renseigner le foreground, la couleur du texte au premier plan..
  •  bg="#884400"  : le background, la couleur d'arrière plan du widget.
  •  width=10  : la largeur du widget (en nombre de caractères si le widget contient du texte).
  •  height=5  : la hauteur du widget. Correspond au nombre de lignes si le widget contient du texte, comme ici
Label texte
Label texte

L'utilisation se fait en deux temps :

  1. la création en mémoire en ligne 12
  2. l'affichage réel dans la fenetre à l'aide de la méthode pack en ligne 13
  3. 12 13
    monLabel = tk.Label(fenetre, text = "Bonjour", fg="white", bg="#884400", width=10, height=5) monLabel.pack()

2-2 Modification après création

Pour modifier les attributs d'un widget, on utilise la méthode configure.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
import tkinter as tk # Création de la fenêtre du logiciel fenetre = tk.Tk() # Configuration de la fenêtre fenetre.geometry("600x300") fenetre.title("Ma super application") fenetre.configure(bg="black") # Création et configuration d'un Label puis affichage monLabel = tk.Label(fenetre, text = "Bonjour", fg="white", bg="#884400", width=10, height=5) monLabel.pack() # Modification du Label monLabel.configure(text="NEW !", fg="black", bg="#BBBBFF") # Surveillance des événements fenetre.mainloop()

La ligne 16 permet de modifier les valeurs choisies au départ. Le carré n'affichage plus le même texte et n'a plus la même couleur.

Label texte modifié
Label texte modifié

Lecture des attributs

Si vous voulez lire et enregistrer la valeur d'un attribut d'un widget, il faut utiliser la méthode cget.

En voici quelques exemples sur les lignes 16 à 18 :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
import tkinter as tk # Création de la fenêtre du logiciel fenetre = tk.Tk() # Configuration de la fenêtre fenetre.geometry("600x300") fenetre.title("Ma super application") fenetre.configure(bg="black") # Création et configuration d'un Label puis affichage monLabel = tk.Label(fenetre, text = "Bonjour", fg="white", bg="#884400", width=10, height=5) monLabel.pack() # Récupération des valeurs des attributs texte = monLabel.cget("text") ecriture = monLabel.cget("fg") fond = monLabel.cget("bg") largeur = monLabel.cget("width") # Surveillance des événements fenetre.mainloop()

Si on lance l'application, qu'on la ferme et qu'on tente de voir le contenu des variables dans la console, on aura ceci :

>>> texte 'Bonjour' >>> ecriture 'white' >>> fond '#884400' >>> largeur 10

3 - Création d'événements à surveiller

Voici le code permettant de modifier le texte du label lorsqu'on clique dessus :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
import tkinter as tk # Déclaration des fonctions def ca_fonctionne(event) : lecture = monLabel.cget('text') if lecture == "Bonjour" : monLabel.configure(text="Ca va ?") else : monLabel.configure(text="Bonjour") # Création de la fenêtre du logiciel fenetre = tk.Tk() # Configuration de la fenêtre fenetre.geometry("600x300") fenetre.title("Ma super application") fenetre.configure(bg="black") # Création et configuration d'un Label puis affichage monLabel = tk.Label(fenetre, text = "Bonjour", fg="white", bg="#884400", width=10, height=5) monLabel.pack() # Activation des événements à surveiller monLabel.bind('<Button-1>', ca_fonctionne) # Surveillance des événements fenetre.mainloop()

3.1 Création d'un premier événement

Evénement

Qu'est-ce qu'un événement pour l'interface ?

Il s'agit d'une modification de l'environnement extérieur : une touche du clavier ou de la souris sur laquelle on appuie, le déplacement de la souris...

La traduction d'événement est event.

Lorsqu'on constate un événement, encore faut-il le gérer. C'est le rôle du gestionnaire d'événement, qu'on traduit par event handler.

Voici un exemple où le clic gauche sur le label modifie le contenu :

Gestionnaire d'événement et fonction-événement Tkinter

C'est ce gestionnaire qui va donner l'ordre d'activer une fonction particulière si cet événement survient.

Pour faire la liaison événement à surveiller ↦ fonction à réaliser, on utilise la méthode bind, appliquée au widget qu'on surveille.

Codification de la liaison avec bind 

  • On active sur le label monLabel
  • la surveillance d'un clic-gauche, identifié par '<Button-1>'
  • qui provoque l'appel à la fonction nommée ca_fonctionne
    24
    monLabel.bind('<Button-1>', ca_fonctionne)

Fonction-événement Tkinter :

    La fonction ca_fonctionne de Tkinter n'est pas une fonction comme les autres : elle DOIT possèder un premier paramètre qui va se remplir automatiquement avec les données de l'événement. Nous en reparlerons juste après.

    4
    def ca_fonctionne(event):

    On note souvent ce paramètre event, e, evt... mais vous pouvez le nommer comme vous voulez : sachez juste que Tkinter va remplir le premier paramètre avec les informations sur l'événement, quelque soit son nom !

    Si on analyse le code de notre exemple, notre fonction n'utilise absolument pas le paramètre event dans son code interne, mais il doit être présent dans les paramètres :

    4 5 6 7 8 9
    def ca_fonctionne(event) : lecture = monLabel.cget('text') if lecture == "Bonjour" : monLabel.configure(text="Ca va ?") else : monLabel.configure(text="Bonjour")
Variable globale monLabel

Notez bien que pour l'instant, nous profitons du fait qu'on peut lire les variables globales depuis une fonction.

Nous verrons plus bas comment programmer l'interface plus proprement.

3.2 Les autres événements sur les touches de la souris

Détection des clics sur les 3 boutons de la souris
24
monLabel.bind('<Button-3>', ca_fonctionne)
  • Le clic-gauche est identifié par '<Button-1>'.
  • Le clic-molette est identifié par '<Button-2>'.
  • Le clic-droit est identifié par '<Button-3>'.
Détection du relachement d'un bouton

Les événements "clics" sont activés dès qu'on appuie. Parfois, il est plus prudent de ne l'activer qu'au relachement. Comment ? En utilisant plutôt ceci :

24
monLabel.bind('<ButtonRelease-1>', ca_fonctionne)
  • '<ButtonRelease-1>' pour le bouton de gauche
  • '<ButtonRelease-2>' pour le bouton central
  • '<ButtonRelease-3>' pour le bouton de droite
La gestion des touches clavier sera vue plus tard.

3.3 Utilisation du paramètre event

Jusqu'à présent, nous avons agi sur monLabel en lisant directement son adresse, déclarée dans le programme principal. Ce n'est pas une très belle façon de programmer.

Objet Event : widget activé et position LOCALE de la souris lors de l'événement

L'objet event contient beaucoup d'informations sur l'événement. Voici comment en récupérer quelques unes :

  • event.widget : l'identifiant-mémoire du widget ayant déclenché l'événement.
  • event.x : la coordonnée locale x de la souris dans le widget au moment de l'événement
  • event.y : la coordonnée locale y de la souris dans le widget au moment de l'événement

Exemple d'utilisation

Voici une interface munie de deux labels : lorsqu'on clique sur l'un des labels, la fonction détecte sur quel label on vient de cliquer et on y affiche les coordonnées LOCALES de la souris sur ce label :

  • (0,0) en haut à gauche et
  • (xMAX, yMAX) en bas à droite.
  • Les coordonnées sont locales car quel que soit le label sur lequel on clique, on obtient les coordonnées de la souris sur ce widget, pas sur l'écran.

Voici le code correspondant :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
import tkinter as tk # Déclaration des fonctions def ca_fonctionne(event): leLabel = event.widget leLabel.configure(text=f"x={event.x} y={event.y}") # Création de la fenêtre du logiciel fenetre = tk.Tk() # Configuration de la fenêtre fenetre.geometry("600x300") fenetre.title("Ma super application") fenetre.configure(bg="black") # Création et configuration des Labels puis affichage monLabel1 = tk.Label(fenetre, text="Label 1 !", fg="white", bg="#884400", width=10, height=5) monLabel2 = tk.Label(fenetre, text="Label 2 !", fg="white", bg="#448800", width=10, height=5) monLabel1.pack() monLabel2.pack() # Activation des événements à surveiller monLabel1.bind('<Button-1>', ca_fonctionne) monLabel2.bind('<Button-1>', ca_fonctionne) # Surveillance des événements fenetre.mainloop()
Objet Event : récupérer le type de l'événement

On peut récupérer avec event.type le type de l'événement qui a déclenché l'appel à votre fonction. On peut ainsi créer éventuellement une fonction générique qui agit différemment en fonction des cas.

Les valeurs sont données dans la première colonne. Ainsi, si un événement possède un type 7, c'est qu'il correspond à la surveillance des entrées dans un widget.

Type (event.type) Evénement Description
4 '<Button-X>' L'utilisateur vient d'appuyer sur l'un des boutons de la souris.
Exemple : <fenetre.bind('<Button-1>', action) pour lier l'action à toute l'application.
5 '<ButtonRelease-1>' L'utilisateur vient de relacher l'un des boutons de la souris.
Exemple : '<ButtonRelease-1>'. A priviligier par rapport au type 4 : l'utilisateur peut sortir du widget pour désactiver son action en cas d'erreur, alors que l'exécution est automatique en cas de type 4 (Button).
6 '<Motion>' L'utilisateur a bougé la souris au dessus du widget.
Exemple : <fenetre.bind('<Motion>', action)
7 '<Enter>' L'utilisateur vient de faire rentrer la souris dans le Widget.
Exemple : <monLabel.bind('<Enter>', action)
L'activation ne se fait que lors de la rentrée.
8 '<Leave>' L'utilisateur vient de faire sortir la souris d'un Widget
Exemple : <monLabel.bind('<Enter>', action)
L'activation ne se fait que lors de la sortie.

Il en existe beaucoup d'autres. Allez voir la documentation si vous désirez faire quelque chose qui n'est pas réalisable avec ceux-ci.

Objet Event : coordonnées ABSOLUES sur l'écran

On peut aussi obtenir les coordonnées du clic sur l'écran en lui-même.

Le point (0,0) est alors le coin supérieur gauche de votre écran, plus du widget lui-même.

Il suffit d'évaluer event.x_root et event.y_root.

Remarque : la fenêtre principale de l'application (fenetre dans le code-exemple) contient également la méthode bind. Vous pouvez donc l'utiliser pour obtenir la position de la souris sur l'application.

4 - Placement des widgets avec place

Pour l'instant, les widgets se placent les uns sous les autres car on utilise simplement la méthode de placement pack sans lui fournir de paramètres.

On peut faire mieux avec cette méthode mais le but n'est pas de faire de vous des spécialistes de Tkinter.

Je parlerai donc simplement de la méthode place.

Méthode d'affichage place

La méthode place permet d'afficher les widgets dans une fenêtre en imposant les coordonnées (x, y) où on veut voir apparaitre le coin supérieur gauche du widget concerné.

Exemple : monLabel.place(x=50, y=100)

A titre d'exemple, une application où le Label texte bouge aléatoirement de place à chaque fois qu'on clique dessus.

  • Lors de la création initiale, on place précisement les widgets (lignes 26 et 27)
  • Dans la fonction bouge, on utilise à nouveau la méthode place en fournissant des coordonnées aléatoires.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
import tkinter as tk import random as rd # Constantes XMAX = 600 YMAX = 300 # Déclaration des fonctions def bouge(event): leLabel = event.widget x = rd.randint(0, XMAX) y = rd.randint(0, YMAX) leLabel.place(x=x, y=y) # Création de la fenêtre du logiciel fenetre = tk.Tk() # Configuration de la fenêtre fenetre.geometry(f"{XMAX}x{YMAX}") fenetre.title("Ma super application") fenetre.configure(bg="black") # Création et configuration des Labels puis affichage monLabel1 = tk.Label(fenetre, text="Label 1 !", fg="white", bg="#884400", width=10, height=5) monLabel2 = tk.Label(fenetre, text="Label 2 !", fg="white", bg="#448800", width=10, height=5) monLabel1.place(x=50, y=50) monLabel2.place(x=100, y=100) # Activation des événements à surveiller monLabel1.bind('<Button-1>', bouge) monLabel2.bind('<Button-1>', bouge) # Surveillance des événements fenetre.mainloop()

5 - Créer des animations avec after

Méthode after

La méthode after appliquée à votre application permet de relancer automatiquement la fonction-argument au bout d'un certain temps exprimée en ms.

10
fenetre.after(500, deplacement)

Ici, on demande donc de lancer un appel à la fonction deplacement au bout de 500 ms, soit 0.5 s.

  • 1000 ms = 1 s
  • 500 ms = 0.5 s
  • 100 ms = 0.1 s
  • 10 ms = 0.01 s
  • 1 ms = 0.001 s

Reprenons l'exemple précédent mais cette fois, les Labels changent de place automatiquement toutes les 0.5 s. Il n'y aura ici aucun événement à surveiller, tous les déplacements sont automatiques.

Comment ?

  • On crée ligne 35 un tableau lesLabels qui contient les références des Labels
  • On active ligne 38 la fonction deplacement
  • Dans cette fonction (voir lignes 10 à 14) :
    • On récupère avec une boucle for ... in (ligne 10) les références successsives des widgets Labels dans la variable de boucle widget. Attention : on lit directement la variable globale lesLabels.
      • On tire aléatoirement deux coordonnées x et y dans la fenêtre (lignes 11-12)
      • On place avec place le widget aux nouvelles coordonnées (ligne 13)
    • On lance avec after l'appel à la même fonction deplacement dans 500 ms, soit 0,5 (ligne 14).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
import tkinter as tk import random as rd # Constantes XMAX = 600 YMAX = 300 # Déclaration des fonctions def deplacement(): for widget in lesLabels : x = rd.randint(0, XMAX - 80) y = rd.randint(0, YMAX - 80) widget.place(x=x, y=y) fenetre.after(500, deplacement) # Création de la fenêtre du logiciel fenetre = tk.Tk() # Configuration de la fenêtre fenetre.geometry(f"{XMAX}x{YMAX}") fenetre.title("Ma super application") fenetre.configure(bg="black") # Création et configuration des Labels puis affichage monLabel1 = tk.Label(fenetre, text="Label 1 !", fg="white", bg="#884400", width=10, height=5) monLabel2 = tk.Label(fenetre, text="Label 2 !", fg="white", bg="#448800", width=10, height=5) monLabel3 = tk.Label(fenetre, text="Label 3 !", fg="white", bg="#008844", width=10, height=5) monLabel4 = tk.Label(fenetre, text="Label 4 !", fg="white", bg="#004488", width=10, height=5) monLabel1.place(x=50, y=50) monLabel2.place(x=100, y=100) monLabel3.place(x=300, y=100) monLabel4.place(x=200, y=200) # Création de la liste des widgets à gérer lesLabels = [monLabel1, monLabel2, monLabel3, monLabel4] # Activation de la fonction d'animation automatique deplacement() # Surveillance des événements fenetre.mainloop()

Dans les prochaines fiches tkinter vous en apprendrez encore un peu plus. D'ici là, n'hésitez pas à poser des questions ou à utiliser un moteur de recherche.

Article publié le 20 11 2019
Dernière modification : 24 11 2019
Auteur : ows. h.