Tkinter
Tkinter (Tk interface) est un module intégré à la bibliothèque standard de Python, permettant de créer des interfaces graphiques :
- des fenêtres,
- des widgets (boutons, zones de texte, cases à cocher, …),
- des évènements (clavier, souris, …).
Tkinter est disponible sur Windows et la plupart des systèmes Unix : les interfaces crées avec Tkinter sont donc portables.
Les noms de Tkinter sont disponibles dans le module tkinter .
Documentation complète de Tkinter : http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html
On se propose de réaliser une petite calculatrice …
Les concepts d’une interface graphique
Première interface
# Import des noms du module from tkinter import * # Création d'un objet "fenêtre" fenetre = Tk() # Titre (Label) titre = Label(fenetre, text = "L'informatique, c'est fantastique !") # Affichage du titre titre.pack() # Ajout des autres widgets # ......................... # Démarrage de la boucle Tkinter (à placer à la fin !!!) fenetre.mainloop()
Remarque : avant Python 3, le module s’appelait Tkinter (avec un T majuscule)
Les objets d’une interface graphique
Les fenêtres
La fenêtre de base de Tkinter se construit avec le constructeur Tk() .
Par défaut, elle porte le nom ‘tk’ et prend la dimension de ce qu’elle contient.
On peut modifier son apparence en passant certaines options lors de sa construction, ou bien après :
fenetre.title("Calculatrice ISN") fenetre.minsize(300,200)
Les widgets
Les éléments graphiques qui apparaissent dans une fenêtre sont nommés widgets. Certains sont statiques (affichage simple) et d’autres permettent une interaction avec l’utilisateur.
Syntaxesyntaxe La syntaxe concerne le signifiant, soit ce qu'est l'énoncé. commune :
Nom_du_widget(parent, [autres arguments])
Tout widget doit être « attaché » à une fenêtre : lors de sa construction, cela correspond à l’argument parent .
Cadre
Un cadre (frame) est un conteneur pour d’autres widgets. Il permet de réaliser des groupes cohérents de widgets.
L’usage veut que l’on place au moins un un cadre dans la fenêtre de base, pour contenir les widgets de l’application :
cadre = Frame(fenetre) cadre.pack()
Label
Les labels permettent d’afficher du texte dans une fenêtre. Le constructeur Label() accepte de nombreux arguments pour la mise en forme du texte. Mais on peut modifier les options de l’objet après sa construction grâce à la méthode .configure() .
Par exemple :
titre.configure(fg = 'red')
Entrée
Une entrée permet à l’utilisateur de saisir un texte sur une seule ligne.
Le constructeur Entry() accepte de nombreux arguments (options d’apparence, …) dont le plus important est la variable Tkinter, objet de type StringVar , permettant de lier de façon dynamique le contenu de l’entrée au reste du programme.
# Saisie de l'expression mathématique : Entrée (Entry) expression = StringVar() expression.set("6*7") # texte par défaut affiché dans l'entrée entree = Entry(cadre, textvariable = expression, width = 30) entree.pack()
Pour bien comprendre le comportement des variables Tkinter, il suffit de l’utiliser dans un autre widget :
# Résultat du calcul sortie = Label(cadre, textvariable = expression) sortie.pack()
Activité :
- Modifier le contenu de l’entrée et observer le comportement du label « sortie » …
Mais pour faire une calculatrice, il faut évaluer l’expression saisie. Le label de sortie ne doit donc pas afficher l’expression mathématique, mais une autre variable contenant le résultat.
resultat = StringVar() sortie = Label(cadre, textvariable = resultat) sortie.pack()
Mais par défaut, une StringVar contient « » . Il faut donc effectuer une opération de calcul, par exemple à travers une fonction :
def calculer(): resultat.set(eval(expression.get()))
Remarque : les méthodes .get() et .set() permettent respectivement d’obtenir la valeur de la variable et d’affecter une nouvelle valeur à la variable.
Il faut à présent trouver un moyen de lancer cette fonction …
Bouton
Les boutons permettent à l’utilisateur d’exécuter une action. Le constructeur Button() attend donc un argument command de type fonction.
# Bouton pour exécuter les calculs bouton = Button(cadre, text = "Calculer", command = calculer) bouton.pack()
Après un appui sur le bouton :
L’inconvénient de la fonction calculer() , c’est qu’elle provoque une erreur dans les cas où l’expression n’est pas évaluable. Il faut donc prévoir cette éventualité :
def calculer(): try: resultat.set(eval(expression.get())) except: pass
Activité :
- Prévoir une modification de la couleur de fond de l’entrée lorsque l’expression n’est pas valide :
On peut également créer un bouton permettant de quitter l’application :
# Bouton pour quitter l'application bouton_quitter = Button(cadre, text = "Quitter", command = fenetre.quit) bouton_quitter.pack()
Bouton radio
Un bouton radio n’est en principe jamais seul : quand l’utilisateur doit faire un choix unique parmi plusieurs possibilités, on utilise typiquement un groupe de boutons radio.
Par exemple, si nous souhaitons contrôler le mode d’affichage du résultat :
# Boutons radio pour sélection du mode d'affichage mode = StringVar() bouton1 = Radiobutton(cadre, text="normal", variable=mode, value="n", command = calculer) bouton2 = Radiobutton(cadre, text="scientifique", variable=mode, value="s", command = calculer) bouton1.pack() bouton2.pack() bouton1.select()
Activité :
- Sachant que pour obtenir une écriture scientifique d’un nombre n il faut employer l’expression ‘%e’ %n , modifier la fonction calculer() .
Case à cocher
Liste
Arrangement des widgets
Jusqu’à présent, tous les widgets se sont placés les uns au dessous des autres, dans l’ordre de leur création, et centrés horizontalement dans la fenêtre.
Il existe différentes méthodes pour gérer les emplacements des widgets dans une fenêtre :
- méthode .place() : positionnement absolu
- méthode .pack() : un gestionnaire simple d’empilement de widgets
- méthode .grid() : arrangement des widgets dans une grille (ou un « tableau »)
Grid
La méthode .grid() permet d’arranger les widgets dans un « tableau », composé de lignes (rows), de colonnes (columns).
Un widget peut occuper plusieurs lignes et/ou plusieurs colonnes adjacentes (rowspan, columnspan).
Il peut être placé dans différentes positions (sticky ; N : nord, E : est, S : sud, W : ouest) dans sa cellule : sticky=NE (haut-droite), SE (bas-droite), SW (bas-gauche), …
Exemples :
titre.grid(row=0, column=0, columnspan=4) entree.grid(row = 1, column = 0, columnspan = 3, sticky = W+E) ...
Activité :
- Réaliser l’arrangement de tous les widgets de la calculatrice de la manière suivante :
- En consultant plus attentivement la documentation complète de la méthode .grid() , améliorer encore le l’affichage et le comportement des widgets (la zone de saisie doit s’ajuster lorsque la taille de la fenêtre est modifiée !).
Documentation complète de grid()
Les événements
Fonctionnalités avancées
Surveillance d’une variable Tkinter
Il peut être particulièrement intéressant d’exécuter une action dès qu’une variable Tkinter a été modifiée. Pour cela, il faut lui attacher un observateur à l’aide de la méthode .trace() :
expression.trace("w", calculer)
Attention : la fonction calculer() sera appelée avec 3 arguments (pas exploités ici). Il faut donc les prévoir dans sa définition :
def calculer(*args): ...
Passer des arguments à une commande
Lorsqu’une commande (widgets Button, RadioButton, …), doit comporter un ou plusieurs arguments, on utilise une fonction lambda :
bouton1 = Radiobutton(cadre, text="normal", variable = mode, value = "n",
command = lambda v= item: calculer(v))
Fermer correctement une application Tkinter
def quitter(): fenetre.destroy() fenetre.protocol('WM_DELETE_WINDOW', quitter)
Structure de base d’un programme Tkinter
from tkinter import * ################################################################################### # Classe définissant l'objet représentant la fenêtre principale de l'application ################################################################################### class Application(Tk): def __init__(self): Tk.__init__(self) self.title("Application du tonnerre !") # Le titre de la fenêtre self.minsize(1550,850) #taille de fenêtre # Une méthode séparée pour construire le contenu de la fenêtre self.createWidgets() # Méthode de création des widgets def createWidgets(self): self.grid() # Choix du mode d'arrangement # Création des widgets # ........... # ........... # ........... # Un bouton pour quitter l'application self.quitButton = Button(self, text = "Quitter", command = self.destroy) self.quitButton.grid() # D'autres méthodes .... # ...................... app = Application() app.mainloop()
Excellente présentation !
Bonjour,
Merci pour cet excellent cours. Il me permet de comprendre Tkinder et de l’utiliser pour mon propre projet. Un grand merci.
Par contre, j’ai passé pas mal de temps à réaliser qu’après
« resultat = StringVar()
sortie = Label(cadre, textvariable = resultat) »
il fallait ajouter :
sortie.pack()
Je le note au cas où d’autres étudiants seraient passés à coté également.
Merci encore pour ce cours !
Mathilde
Merci pour la remarque, j’ai ajouté la ligne.
Bonjour,
Actuellement étudiant en deuxième année de Master Ingénierie et Ergonomie de l’Activité Physique, je travaille sur la conception d’un miroir connecté permettant d’afficher différentes informations.
J’utilise un Raspberry Pi 3 et le langage python pour réaliser l’interface graphique.
Je souhaiterais savoir comment afficher un widget météo (html) sur une interface réalisé en python. Est ce que Tkinter permet de réaliser ceci? Dois-je utiliser une autre bibliothèque?
Je vous remercie par avance pour votre réponse.
Romain
Bonjour
Je ne suis pas sûr de bien comprendre …
Si vous réalisez un serveur web (client+serveur), pour afficher un widget sur un page html, il ne faut pas utiliser tkinter, car ce dernier est une interface graphique pour faire des applications « locales ».
Je vous conseille plutôt de générer du code html5 avec python/flask (coté serveur)
Ou bien d’utiliser du javascript.
Si vous réalisez une application « locale », tkinter peut convenir, mais tout dépend de ce que vous voulez afficher dans votre widget.
CF