Formation I.S.N.

Le module tkinter

tkinter est un module de «gadgets graphiques» (widgets - contraction de windows et gadget) intégré par défaut dans Python. On utilisera cette bibliothèque graphique en raison de sa simplicité. Il existe aussi d'autres bibliothèques de ce type (wxPython, pyQT, pygame...) mais elles ne seront pas abordées au cours de cette formation.

Un manuel de référence sur tkinter (168 pages en anglais !) est disponible en cliquant sur ce lien.

Le principe général est :

  • de créer une fenêtre graphique (cf. ci-contre) ;
  • puis de placer et organiser des éléments (boutons, textes, zones de dessin, etc...) à l'intérieur de cette fenêtre.

Important - Avant de commencer

Même si la formation d'aujourd'hui va vous apprendre le B.A.-BA pour programmer une interface graphique, il ne faut surtout pas oublier...

qu'une interface graphique n'est qu'une surcouche d'un programme déjà fonctionnel !

De manière générale, on commence par concevoir un code fonctionnel en mode console puis on ajoute fenêtre, boutons, canevas et interaction afin de rendre ce programme plus convivial dans son utilisation.

Organiser une fenêtre

Une fenêtre est tout simplement un rectangle affiché à l'écran dans lequel on place d'autres objets graphiques (widgets) après les avoir affectés à des variables.

tkinter permet de manipuler de très nombreux objets graphiques (comme l'atteste le document de référence). Pour éviter de se perdre entre tous ces widgets, on se limitera dans cette formation à :

Widget Description
Label() Zone d'affichage de texte.
Entry() «Formulaire» qui permet de récupérer du texte saisi par l'utilisateur.
Button() Un bouton sur lequel cliquer.
Canvas() Canevas très «souple» qui correspond à une zone de dessin ou d'animation. C'est souvent le widget le plus utilisé.

Une fois les widgets créés, il faut anticiper leur positionnement dans la fenêtre grâce à la méthode .grid() appliquée au widget :


widget_nom.grid(row=..., column=...)
				

La fenêtre est alors «partagée» virtuellement en lignes (row) et colonnes (column) numérotées à partir de 0 (valeurs par défaut). On obtient ainsi des «cellules» (comme la feuille de calcul d'un tableur) dans lesquelles seront placées les différents widgets.

Outre les numéros de ligne (row = a) et de colonne (column = b) indiquant la «cellule» dans laquelle placer le widget, la méthode .grid() accepte des paramètres optionnels :

  • rowspan = n fusionne n cellules verticalement depuis la cellule dans laquelle le widget est positionné.
  • columnspan = n fusionne n cellules horizontalement depuis la cellule dans laquelle le widget est positionné.
  • padx et pady : écart (en pixels) entre le widget et le bord de sa «cellule» (horizontal puis vertical).
  • sticky = position permet de positionner le widget dans la cellule si celle-ci est trop grande pour lui.
    position peut prendre pour valeurs N, SW, E+W, etc...

La disposition des différents widgets dans une fenêtre peut modifier sensiblement le comportement d'un programme. Anticiper l'apparence désirée à l'aide d'un papier et d'un crayon se révèle vite indispensable..

Exemple d'analyse de fenêtre

En observant l'organisation de la fenêtre, placez dans le tableau ci-dessous les types des différents widgets en cohérence avec leur position.

  • Une solution

Fenêtre principale

On commence par définir une une fenêtre « vide », de dimensions modifiables à loisir. Les trois boutons en haut à droite de la fenêtre sont actifs :


##----- Importation des Modules -----##
from tkinter import *

##----- Création de la fenêtre -----##
fen = Tk()                          # Objet stockée dans la variable "fen"

##-----Programme principal-----##
fen.mainloop()                      # Boucle d'attente des événements
				

La fenêtre stockée dans la variable fen est un objet informatique. Pour modifier (manipuler) cet objet, il faut lui appliquer une méthode selon la syntaxe :


objet.methode(parametres_eventuels)
				

Méthodes qu'on peut appliquer à une fenêtre

Méthode(paramètre) Description
fen.title('titre') 'titre' de la fenêtre sous forme de chaîne de caractères (string)
fen.geometry('AxB+C+D') Fenêtre de A pixels de large et B pixels de haut. Le coin supérieur gauche de la fenêtre est situé à C pixels en abscisses et D pixels en ordonnées du coin supérieur gauche de l'écran.
fen.mainloop() Obligatoire pour que la fenêtre reste ouverte !

Définir un bouton

L'instruction :


bouton_nom = Button(parent, text='…', command=fonction)
					

affecte un widget Button() à la variable intitulée bouton_nom. De plus,

  • Ce bouton se place dans le widget contenu dans la variable parent (généralement une fenêtre).
  • Le texte '…' sera affiché sur le bouton et le clic lancera la fonction fonction.

Attention !

La fonction appelée doit être définie avant la création du bouton. De plus, cette fonction ne doit pas comporter d'argument, ce qui nécessite de faire preuve d'ingéniosité (ou d'utiliser la fonction lambda qui sera utilisée dans un des exercices).

Méthodes qu'on peut appliquer à un bouton stocké dans btn

Méthode(paramètre) Description
btn.grid(row=…, column=…) Voir le paragraphe Organiser une fenêtre
btn.configure(para=…) Modifie le(s) paramètre(s) indiqué(s).
Avec text='…', le texte affiché change.
btn.destroy() Suppression du bouton.

Exemple : Cas particulier du bouton [Quitter]

On complète la fenêtre créée dans le paragraphe précédente avec un bouton de fermeture :


##----- Importation des Modules -----##
from tkinter import *

##----- Création de la fenêtre -----##
fen = Tk()                          # Stockée dans la variable "fen"
fen.title('Ma première fenêtre')    # Titre de la fenêtre

##----- Création des boutons -----##
bouton_quitter = Button(fen, text='Quitter')


##-----Programme principal-----##
fen.mainloop()                      # Boucle d'attente des événements
				
  1. Copiez ce code dans un environnement en Python puis exécutez-le. Que se passe-t-il ?
  2. Complétez la ligne 10 pour que le bouton [Quitter] s'affiche correctement dans la fenêtre créée.
  3. Une fois le bouton apparu, cliquez dessus. Que se passe-t-il ?
  4. Il faut associer une fonction à la commande que doit exécuter le bouton_quitter. La méthode qui permet de fermer une fenêtre (stockée dans la variable fen) est fen.destroy().
  • Question 1°/
  • Question 2°/
  • Question 3°/
  • Question 4°/
Le bouton [Quitter] ne s'affiche pas dans la fenêtre.

Un exemple de code :


##----- Importation des Modules -----##
from tkinter import *

##----- Création de la fenêtre -----##
fen = Tk()                          # Stockée dans la variable "fen"
fen.title('Ma première fenêtre')    # Titre de la fenêtre

##----- Création des boutons -----##
bouton_quitter = Button(fen, text='Quitter')
bouton_quitter.grid(row=0, column=0)


##-----Programme principal-----##
fen.mainloop()                      # Boucle d'attente des événements
						
Il n'y a pas de commande associée au bouton donc un clic sur celui-ci ne déclenche rien...

Attention, pas de parenthèses pour faire appel à une fonction par l'intermédiaire d'un bouton...


##----- Importation des Modules -----##
from tkinter import *

##----- Création de la fenêtre -----##
fen = Tk()                          # Stockée dans la variable "fen"
fen.title('Ma première fenêtre')    # Titre de la fenêtre

##----- Création des boutons -----##
bouton_quitter = Button(fen, text='Quitter', command=fen.destroy)
bouton_quitter.grid(row=0, column=0)


##-----Programme principal-----##
fen.mainloop()                      # Boucle d'attente des événements
						

Définir un zone de texte

L'instruction :


zone_nom = Label(parent, text='BlaBla')
					

affecte un widget Label() à la variable intitulée zone_nom. De plus,

  • Cette zone de texte se place dans le widget contenu dans la variable parent (généralement une fenêtre).
  • Elle peut contenir aussi bien du texte (sic !) que des images (voir le chapitre sur les Canvas pour la méthode).

Méthodes qu'on peut appliquer à une zone de texte stockée dans txt

Méthode(paramètre) Description
txt.grid(row=…, column=…) Voir le paragraphe Organiser une fenêtre
txt.configure(para=…) Modifie le(s) paramètre(s) indiqué(s).
Avec text='…', le texte affiché change.
txt.destroy() Suppression de la zone de texte.

Suite de l'exemple

Complétez le programme ci-dessous pour qu'il affiche une fenêtre avec une zone de texte ayant l'apparence ci-contre :


##----- Importation des Modules -----##
from tkinter import *

##----- Création de la fenêtre -----##
fen = Tk()                          # Stockée dans la variable "fen"
fen.title('Ma première fenêtre')    # Titre de la fenêtre

##----- Création des boutons -----##
bouton_quitter = Button(fen, text='Quitter', command=fen.destroy)
bouton_quitter.grid(row = 0, column = 0)

##----- Création des zones de texte -----##
texte_aide =                        # A compléter...

##-----Programme principal-----##
fen.mainloop()                      # Boucle d'attente des événements
				
  • Une solution

Il ne faut pas oublier de modifier les paramètres de la méthode .grid() appliquée au bouton_quitter.


##----- Importation des Modules -----##
from tkinter import *

##----- Création de la fenêtre -----##
fen = Tk()                          # Stockée dans la variable "fen"
fen.title('Ma première fenêtre')    # Titre de la fenêtre

##----- Création des boutons -----##
bouton_quitter = Button(fen, text='Quitter', command=fen.destroy)
bouton_quitter.grid(row = 1, column = 0, sticky=E)

##----- Création des zones de texte -----##
texte_aide = Label(fen, text='Appuyer sur le bouron pour fermer la fenêtre')
texte_aide.grid(row = 0, column = 0)

##-----Programme principal-----##
fen.mainloop()                      # Boucle d'attente des événements
						

Définir un formulaire

L'instruction :


saisie_nom = Entry(parent, textvariable=StringVar())
					

affecte un widget Entry() à la variable intitulée saisie_nom. De plus,

  • Ce formulaire se place dans le widget contenu dans la variable parent (généralement une fenêtre).
  • On peut récupérer le texte entré par l'utilisateur avec la méthode .get().

Méthodes qu'on peut appliquer à un formulaire stocké dans form

Méthode(paramètre) Description
forme.grid(row=…, column=…) Voir le paragraphe Organiser une fenêtre
form.get() Permet de récupérer le texte entré par l'utilisateur.
Attention de bien affecter ce texte à une variable...
form.configure(para=…) Modifie le(s) paramètre(s) indiqué(s).
form.destroy() Suppression du formulaire.

Fin de l'exemple : fenêtre « interactive »

Le but de cet exemple est de concevoir la fenêtre ci-contre. L'utilisateur est invité à entrer son prénom. Une fois le bouton [Valider] enclenché, s'affiche le message « Bonjour … » où les pointillés … sont remplacés par le prénom saisi.

Compléter la définition de la fonction prenom() ainsi que les paramètres des différentes méthodes .grid() afin que le programme devienne fonctionnel.


##----- Importation des Modules -----##
from tkinter import *


##----- Définitions des Fonctions -----##
def prenom():
    """ Entrées : Fonction déclenchée par le bouton - pas d'entrée
        Sorties : Insère le prénom de l'utilisateur dans une zone de texte"""
    # A compléter
	
	
##----- Création de la fenêtre -----##
fen = Tk()
fen.title('Fenêtre interactive')


##----- Création des boutons -----##
bouton_valider = Button(fen, text='Valider', command=prenom)
bouton_valider.grid(row = …, column = …, padx = …, pady = …)

bouton_quitter = Button(fen, text='Quitter', command=fen.destroy)
bouton_quitter.grid(row = …, column = …, padx = …, pady = …)


##---- Création des zones de texte -----##
texte_question = Label(fen, text='Entrez votre prénom puis validez :')
texte_question.grid(row = …, column = …, padx = …, pady = …)

texte_reponse = Label(fen, text='')
texte_reponse.grid(row = …, column = …, …………………………, padx = …, pady = …)


##----- Création des formulaires -----##
form_texte = Entry(fen, textvariable=StringVar())
form_texte.grid(row = …, column = …, padx = …, pady = …)


##----- Programme principal -----##
fen.mainloop()
				
  • Une solution

##----- Importation des Modules -----##
from tkinter import *


##----- Définitions des Fonctions -----##
def prenom():
    """ Entrées : Fonction déclenchée par le bouton - pas d'entrée
		Sorties : Insère le prénom de l'utilisateur dans une zone de texte"""
	a = form_texte.get()						# Un formulaire est un objet - variable globale
	texte_reponse.configure(text='Bonjour ' + a)

	
##----- Création de la fenêtre -----##
fen = Tk()
fen.title('Fenêtre interactive')


##-----Création des boutons-----##
bouton_valider = Button(fen, text='Valider', command=prenom)
bouton_valider.grid(row = 2, column = 0, padx = 3, pady = 3)

bouton_quitter = Button(fen, text='Quitter', command=fen.destroy)
bouton_quitter.grid(row = 2, column = 1, padx = 3, pady = 3)


##-----Création des zones de texte-----##
texte_question = Label(fen, text='Entrez votre prénom puis valider :')
texte_question.grid(row = 0, column = 0, padx = 3, pady = 3)

texte_reponse = Label(fen, text='')
texte_reponse.grid(row = 1, column = 0, columnspan = 2, padx = 3, pady = 3)


##-----Création des formulaires-----##
form_texte = Entry(fen, textvariable=StringVar())
form_texte.grid(row = 0, column = 1, padx = 3, pady = 3)


##-----Programme principal-----##
fen.mainloop()
						

Méthodes applicables à n'importe quel widget

Les méthodes ci-dessous s'appliquent à n'importe quel widget. Elles permettent de récupérer des informations sur ces widgets dans l'éventualité où certains paramètres ont été modifiés au cours du programme.

  • Récupérer sous forme d'entier la hauteur actuelle (en px) d'un widget :
    
    h = widget_nom.winfo_reqheight()
    						
  • Récupérer sous forme d'entier la largeur actuelle (en px) d'un widget :
    
    h = widget_nom.winfo_reqwidth()
    						
  • Supprimer un widget (et tous ses widgets enfants) :
    
    widget_nom.destroy()