🖥️ GUI via Tkinter#
Note
Tkinter est un module de base intégré dans Python, normalement vous n’avez rien de plus à installer pour pouvoir l’utiliser.
Tkinter sert à réaliser des interfaces graphiques pour l’utilisateur (GUI) à l’aide d’un ensemble de composants graphiques (widgets).
L’un des avantages de Tkinter est sa portabilité sur les OS les plus utilisés par le grand public. Celui-ci permet la création simplement et rapidement d’interface graphique.
Toutefois celle-ci doivent être créer à la « main » étant donnée qu’aucun éditeur WYSIWYG n’existe pour cette technologie.
Hello Tkinter#
Voici le code source du oh grand classique HelloWorld
from tkinter import *
frame = Tk()
label = Label(frame, text="Hello World")
label.pack()
frame.mainloop()
Note
La dernière instruction root.mainloop() permet à l’application de recevoir des informations de la souris et du clavier (entre autres).
from tkinter import *
root = Tk()
root.title('Simple exemple')
quit_button = Button(root, text='Quitter', command=root.quit)
quit_button.pack()
root.mainloop()
Terminologie de Tkinter#
Avant d’entrer dans le coeur du sujet, voici quelques termes utilisés fréquemment ensuite:
- Fenêtre (window)
Ce terme prend des sens différents suivant le contexte, mais en général il renvoie à une aire rectangulaire quelque part sur votre écran.
- Fenêtre mère (top-level window)
Une fenêtre qui existe de manière indépendante sur l’écran. Elle sera décorée conformément à votre gestionnaire de bureau et munie des petits boutons habituels. On peut la déplacer et généralement la redimensionner même si votre application peut limiter cela.
- Composant graphique (widget)
terme générique désignant tous les éléments qui forment l’interface graphique utilisateur. Par exemple, les boutons (buttons), les boutons « radio » (radiobuttons), les champs de saisie (entry), les étiquettes (labels), les cadres (frames) …
- Cadre (frame)
Dans tkinter, c’est l’unité de base pour l’organisation d’une mise en forme complexe. Un cadre est une zone rectangulaire qui peut contenir d’autres composants graphiques (widgets).
- enfant, parent
Lorsqu’un composant graphique est créé, une relation parent/enfant est établie. Par exemple, si on place une étiquette (label) dans un cadre (frame), le cadre est le parent de l’étiquette.
Widgets#
La création d’interface graphique passe par l’ajout au sein de la fenêtre de widgets. Il exite de très nombreux widgets différents au sein de Tkinter, nous en verrons que quelques uns par la suite. Pour en savoir plus rendez-vous sur cette page.
Les boutons#
Les boutons permettent de proposer une action à l’utilisateur. Dans l’exemple ci-dessous, on lui propose de fermer la fenêtre.
from tkinter import *
frame = Tk()
exit_button=Button(frame, text="Close me!", command=frame.quit)
exit_button.pack()
frame.mainloop()
Les labels#
Les labels sont des espaces prévus pour écrire du texte. Les labels servent souvent à décrire un widget comme un input, nous en avons déjà vu un plus haut.
input#
Comme leurs nom l’indique, ils permettent la saisie d’information par l’utilisateur.
from tkinter import *
frame = Tk()
value = StringVar()
value.set("texte par défaut")
entry = Entry(framre, textvariable=value, width=30)
entry.pack()
frame.mainloop()
Indication
La valeur de l’input sera stocké dans value
.
Les alertes#
Pour pouvoir utiliser les alertes de votre os, vous pouvez importer le module messagebox
from tkinter.messagebox import *
from tkinter import *
frame = Tk()
def callback():
if askyesno('Titre 1', 'Êtes-vous sûr de vouloir faire ça?'):
showwarning('Titre 2', 'Tant pis...')
else:
showinfo('Titre 3', 'Vous avez peur!')
showerror("Titre 4", "Aha")
Button(text='Action', command=callback).pack()
frame.mainloop()
Gestionnaires de positionnement#
Comment organiser les widgets dans une fenêtre ?
Bien qu’il y ait différents gestionnaires de positionnement (geometry managers) dans tkinter, nous retiendrons plus spécialement le gestionnaire .grid()
. Ce gestionnaire « découpe » chaque fenêtre ou cadre en une grille formée de lignes et de colonnes.
Une cellulle (cell) est la zone d’intersection d’une ligne et d’une colonne.
La largeur de chaque colonne est la largeur de la plus large cellule qu’elle contient.
La hauteur de chaque ligne est la hauteur de la plus large ligne qu’elle contient.
Pour les composants graphiques (widgets) qui n’occupent pas toute la surface de leur cellule, on peut indiquer quoi faire de l’espace restant : à l’extérieur du widget, ou en étirant celui-ci pour le combler dans la direction horizontale ou verticale.
Il est possible de regrouper (spanning) plusieurs cellule en une plus large (ou plus haute).
Lorsqu’on crée un widget, il n’apparaît pas jusqu’à ce qu’il soit positionné au moyen d’un gestionnaire de positionnement. Ainsi, construction et placement du widget se font en deux temps:
truc = Constructeur(parent, ...)
truc.grid(...)
où Constructeur est l’une des classes de widget comme Button, Frame, … et parent
est le widget parent dans lequel le widget enfant est construit. Tous les widgets dispose de la méthode .grid()
qui s’utilise pour préciser son emplacement dans une grille.
from tkinter.messagebox import *
from tkinter import *
def button_validation_callback():
showinfo('Greeting', 'Hello %s' % value.get())
root = Tk()
root.title("Greetings")
value = StringVar()
value.set('Default value')
label = Label(root, text="Hello World")
label.grid(column=0, row=0)
input_r = Entry(root, textvariable=value)
input_r.grid(column=1, row=0)
button_validation = Button(root, text="Say it !", command=button_validation_callback)
button_validation.grid(row=1, column=1)
root.mainloop()
Toutefois notre interface ne se redimensionne pas correctement, pour ce faire nous devons ajouter les lignes de code suivante après la déclaration de notre fenêtre:
root.rowconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
Que se passe t’il si nous rajoutons l’option sticky à notre input:
input_r.grid(column=1, row=0, sticky='nsew')
Une première mise en pratique#
Nous venons de découvrir comment créer des interfaces graphiques en python. Mettons en pratique ce nouveau savoir pour créer une application basique qui se chargera de compter la longueur d’un texte pour nous en adoptant bien sûr l’approche TDD.

Il vous est recommandé d’utiliser le composant Text
de Tkinter, voici quelques indications:
textarea = Text(root, wrap='word') # création du composant
textarea.insert(END, "Hello World") # insertion d'un texte
textarea.get("0.0", END) # récupération de l'ensemble du texte
Indication
from tkinter.ttk import *
root = Tk()
icon = PhotoImage(file='icon.png')
root.title("Counter")
root.iconphoto(False, icon)
Tkinter et la 2D#
La librairie Tkinter
intégre un composant Canvas
, un canvas (ou canevas) est une zone rectangulaire destinée à contenir des dessins ou d’autres figures complexes.
Voici comment tracer une ligne. La méthode create_line(coords, options)
permet de tracer une ligne droite.
Les coordonnées coords
sont données sous forme de quatre nombres entiers: \(x1, y1, x2, y2\).
Cela signifie que la ligne va du point \((x1, y1)\) au point \((x2, y2)\). Après ces coordonnées suit une liste de valeurs séparées par des virgules, ce sont des paramètres supplémentaires qui peuvent être vides. Nous définissons, par exemple, la couleur de la ligne.
from tkinter import *
master = Tk()
canvas_width = 80
canvas_height = 40
canvas = Canvas(master,
width=canvas_width,
height=canvas_height)
canvas.pack()
line_y = canvas_height / 2
canvas.create_line(0, y, canvas_width, y, fill="#476042")
master.mainloop()
Voici le code pour tracer quelques figures géométriques:
from tkinter import *
master = Tk()
canvas = Canvas(master, width=200, height=100)
canvas.pack()
canvas.create_rectangle(50, 20, 150, 80, fill="#476042")
canvas.create_rectangle(65, 35, 135, 65, fill="yellow")
canvas.create_line(0, 0, 50, 20, fill="#476042", width=3)
canvas.create_line(0, 100, 50, 80, fill="#476042", width=3)
canvas.create_line(150, 20, 200, 0, fill="#476042", width=3)
canvas.create_line(150, 80, 200, 100, fill="#476042", width=3)
master.mainloop()
Gestion du clic#
Pour gérer le clic sur un canvas nous devons définir un callback que nous allons lier au clic gauche sur notre canvas
from tkinter import *
import datetime
master = Tk()
canvas = Canvas(master, width=700, height=250)
canvas.pack()
def click_callback(event):
x1 = event.x
y1 = event.y
color = 'blue'
if event.num == 1:
color = 'red'
elif event.num == 3:
color = 'yellow'
canvas.create_rectangle(x1, y1, x1 + 20, y1 + 20, fill=color)
canvas.bind('<Button-1>', click_callback)
canvas.bind('<Button-3>', click_callback)
master.mainloop()
Gestion des animations#
from tkinter import *
import datetime
master = Tk()
canvas = Canvas(master, width=700, height=250)
canvas.pack()
element_id = canvas.create_oval(10, 20, 30, 40, fill='blue')
def anim():
if datetime.datetime.now().second % 2 == 0:
canvas.itemconfig(element_id, fill='yellow')
else:
canvas.itemconfig(element_id, fill='blue')
master.after(500, anim)
anim()
master.mainloop()