Peut-être que vous venez de commencer à apprendre Python et que vous avez créé une ou deux applications simples. Toutes nos félicitations! Mais, et maintenant ? Eh bien, que diriez-vous de créer une interface utilisateur graphique ("GUI") pour interagir avec votre nouvelle application Python brillante ?
Il existe plusieurs options pour créer des applications GUI avec Python, notamment PyQt et wxPython . Ce guide, cependant, vous présentera Tkinter .
Tkinter , qui signifie "Tk interface", est le standard de Python pour la construction d'interfaces graphiques et est inclus dans la Python Standard Library . Il s'agit d'une liaison avec la boîte à outils Tk GUI , une bibliothèque libre et open source de widgets GUI qui peut être utilisée pour créer des interfaces graphiques dans une variété de langages de programmation.
Ce didacticiel décrit la conception d'une application graphique de base qui affiche l'heure locale dans un fuseau horaire sélectionné par l'utilisateur. Les étapes construisent l'application progressivement et décrivent certains des concepts clés lors de l'utilisation de Tkinter , y compris la disposition des éléments de l'interface graphique, la capture des entrées de l'utilisateur et la liaison des éléments de l'interface graphique aux méthodes de rappel.
Pour compléter ce guide, vous aurez besoin de :
pip
installé.pytz
. La bibliothèque peut être installée à l'aide de pip
.
pip install pytz
Ce guide utilisera indifféremment la terminologie fenêtre racine et fenêtre principale .
Créez une nouvelle application Python nommée timezone.py
et ajoutez les instructions d' import
suivantes pour importer les modules Tkinter
, datetime
et pytz
.
import tkinter as tk import datetime import pytz
Ce guide intègre l'ensemble des fuseaux horaires des États-Unis qui représentent une petite fraction des fuseaux horaires pris en charge par pytz
. La fonctionnalité de l'application peut être étendue en ajoutant des noms de fuseau horaire pytz
supplémentaires. Une liste complète des fuseaux horaires disponibles avec pytz
peut être générée en exécutant la commande suivante :
print(pytz.all_timezones)
L'ensemble des fuseaux horaires des États-Unis disponibles via pytz
est spécifié sous forme de liste.
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]
L'instanciation de la classe Tk
crée une fenêtre racine qui servira de fenêtre principale de l'interface graphique de l'application de fuseau horaire.
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk()
Cette étape configure la fenêtre racine, en particulier son titre, sa géométrie et sa capacité de redimensionnement.
Le titre de la fenêtre est défini à l'aide de la méthode du title
.
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application")
Les valeurs de largeur et de hauteur de la fenêtre, exprimées en pixels, peuvent être affectées à des variables pour rendre le code plus facile à suivre.
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175
La fenêtre principale peut être placée n'importe où sur l'écran, par exemple au centre, dans le coin supérieur gauche, etc. Une fenêtre centrée offre un "look" agréable et la position centrale de la fenêtre principale peut être déterminée à l'aide de la fenêtre winfo_screenwidth()
et winfo_screenheight()
avec quelques calculs simples. Ces deux méthodes renvoient la largeur et la hauteur de l'écran qui sont utilisées pour calculer les coordonnées (x,y) appropriées pour centrer la fenêtre principale. Comme pour la largeur et la hauteur de la fenêtre, les valeurs de position centrale peuvent également être affectées à des variables pour rendre le code plus lisible.
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2)
Notez que les valeurs center_x
et center_y
sont également exprimées en pixels et int
est utilisé pour garantir que les deux valeurs calculées sont des entiers.
La géométrie de la fenêtre root
, qui spécifie la taille et la position de la fenêtre principale, est définie à l'aide de la méthode de geometry
de la fenêtre racine. Pour simplifier les choses, vous pouvez utiliser un littéral sting formaté, ou f-string , qui interpolera les expressions de variables géométriques au moment de l'exécution. Selon le bloc de code suivant, le littéral f-string est passé à la méthode geometry
en tant que paramètre.
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")
Le redimensionnement de la fenêtre racine le long de ses axes x et y peut être défini via la méthode de resizable
de la fenêtre racine. La méthode de resizable
accepte les paramètres de height
et de width
, dans cet ordre. Une valeur True
ou différente de zéro pour l'un ou l'autre des paramètres spécifie que la fenêtre principale est redimensionnable le long de l'axe associé. Une valeur False
ou 0
pour l'un ou l'autre des paramètres spécifie que la fenêtre principale n'est pas redimensionnable le long de l'axe donné. L'application de minuterie utilisera la valeur False
pour la hauteur et la largeur afin d'empêcher le redimensionnement de la fenêtre principale.
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False)
Les widgets peuvent être disposés en haut de la fenêtre principale de différentes manières à l'aide des gestionnaires de géométrie . Généralement, les widgets peuvent être organisés de 3 manières :
Compressé à l'aide de la méthode pack()
. Le gestionnaire de géométrie pack()
organise les widgets en blocs avant qu'ils ne soient ajoutés à une fenêtre racine ou à un widget parent. Une façon imparfaite mais peut-être utile de penser à l' emballage est de penser à ajouter des articles d'épicerie dans un sac d'épicerie. Les articles ne sont pas nécessairement ajoutés à des emplacements prédéfinis dans le panier. Au lieu de cela, ils sont emballés les uns après les autres, utilisant l'espace disponible jusqu'à ce que tous les articles aient été placés dans le sac. Le gestionnaire de géométrie pack()
fonctionne de manière similaire.
Placé à l'aide de la méthode place()
. Le gestionnaire de géométrie place()
place les widgets dans des positions spécifiques et prédéfinies dans la fenêtre racine ou le widget parent. Ce gestionnaire de géométrie est évidemment utile lors de la création de mises en page précises de l'interface graphique.
Arrangé sous forme de grille à l'aide de la méthode grid()
. Les grilles sont des tableaux de lignes/colonnes à 2 dimensions. Les widgets sont ajoutés à une grille en spécifiant la ligne et la colonne particulières où le widget doit être placé. Les grilles sont configurées à l'aide des méthodes columnconfigure
et rowconfigure
de la fenêtre racine. Chacune de ces méthodes possède un index
et un attribut de weight
. L'attribut index
spécifie la position de la colonne ou de la ligne en utilisant une base de départ de 0
. L'attribut weight
spécifie la taille d'une colonne ou d'une ligne particulière par rapport aux autres colonnes. Par exemple, si la colonne 0 a le poids 1
et la colonne 1 a le poids 3
, alors la colonne 1 sera 3 fois plus grande que la colonne 0 .
Les grilles sont pratiques pour placer des éléments les uns à côté des autres et elles sont relativement simples à mettre en œuvre. L'application de fuseau horaire utilisera une grille de fenêtre principale divisée en 4 colonnes égales.
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1)
Dans cette étape, les widgets sont ajoutés à la grille de la fenêtre principale définie à l'étape 4. L'application de fuseau horaire utilisera 3 widgets TKinter :
Label
Listbox
Button
Les widgets Label
et Button
de Tkinter sont exactement comme ils sont nommés. Le widget Label
permet au programmeur d'afficher du texte (c'est-à-dire une étiquette), et le widget Button
est utilisé pour afficher des boutons. Le widget Listbox
est utilisé pour sélectionner une valeur (ou des valeurs) dans une liste d'options.
Bien entendu, il existe d'autres widgets que les 3 répertoriés ci-dessus, tels que les SpinBox
, Entry
et Message
. La documentation formelle des commandes Tk est une ressource utile pour en savoir plus sur les widgets disponibles via la boîte à outils Tk.
Une instance de chaque classe de widget est créée pour un widget donné utilisé avec la conception de l'interface graphique. L'application de fuseau horaire utilise 4 instances de widget : 2 widgets Label
, 1 widget Listbox
et 1 widget Button
.
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) # Instance of Label widget class for selection prompt. select_timezone_label = tk.Label(root, text="Please select a timezone.") # Instance of Listbox class for selection of timezone from list. list_var = tk.Variable(value=timezones) select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1) # Instance of Button class to get the local time in the selected timezone. select_timezone_button = tk.Button(root, text="Get Time") # Second instance of the Label class to display the local time in the selected timezone. time_label = tk.Label(root, text="")
Comme on le voit dans le bloc de code ci-dessus, chaque instance de widget est "attachée" à la fenêtre root
. Le widget Listbox
nécessite également l'instanciation d'une classe spéciale Tkinter Variable()
qui est utilisée pour fournir au widget la liste des options de fuseau horaire que l'utilisateur peut sélectionner via l' Listbox
listvariable
. Le texte affiché par chaque widget Label
peut être configuré à l'aide de l'attribut text
. La valeur de texte pour time_label
est laissée vide car elle sera définie dynamiquement chaque fois que l'utilisateur "obtiendra" l'heure d'un fuseau horaire sélectionné.
Les instances de widget créées à l'étape 5a peuvent être placées sur la grille définie à l'étape 4 à l'aide de la méthode grid()
. L'application de fuseau horaire utilisera les attributs de méthode grid()
suivants pour définir la mise en page :
column
: spécifie la colonne particulière où le widget sera placé en utilisant une base 0
.
row
: spécifie la ligne particulière où le widget sera placé en utilisant une base 0
.
columnspan
: spécifie que le widget doit s'étendre sur le nombre de colonnes spécifié. Par exemple, un widget avec une valeur columnspan=3
s'étendra sur 3 colonnes même si le widget lui-même est inférieur à 3 colonnes.
sticky
: le comportement par défaut de Tkinter est de placer un widget au centre horizontal et vertical de la cellule (c'est-à-dire une position de ligne/colonne particulière) où il est placé. Ce comportement par défaut peut être remplacé à l'aide de l'attribut sticky
qui utilise des valeurs de type boussole, notamment NW
, N
, NE
, W
, E
, SW
, S
et SE
, pour aligner le widget à un emplacement particulier dans la cellule du widget. Par exemple, sticky=tK.W
spécifie que le widget doit être aligné sur le coin ouest de sa cellule de grille. De manière analogue, sticky=tK.E
spécifie que le widget doit être aligné sur le coin est de sa cellule de grille.
padx
, pady
: Les attributs padx
et pady
sont utilisés pour ajouter respectivement un remplissage sur l'axe des x et l'axe des y avec des valeurs spécifiées en pixels. Naturellement, le rembourrage peut fournir une interface graphique d'aspect plus professionnel garantissant que les widgets ne "se heurtent" pas directement aux bords de la fenêtre racine ou d'autres widgets.
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) # Instance of Label widget class for selection prompt. select_timezone_label = tk.Label(root, text="Please select a timezone.") # Instance of Listbox class for selection of timezone from list. list_var = tk.Variable(value=timezones) select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1) # Instance of Button class to get the local time in the selected timezone. select_timezone_button = tk.Button(root, text="Get Time") # Second instance of the Label class to display the local time in the selected timezone. time_label = tk.Label(root, text="") # Place widgets on grid. select_timezone_label.grid(column=0, row=0, columnspan=4, sticky=tk.W, padx=10, pady=10) select_timezone_listbox.grid(column=0, row=1, columnspan=3, sticky=tk.EW, padx=10, pady=10) select_timezone_button.grid(column=4, row=1, sticky=tk.E, padx=10, pady=10) time_label.grid(column=0, row=4, columnspan=4, sticky=tk.W, padx=10, pady=10)
Une méthode de rappel doit être définie pour gérer les événements lorsque l'utilisateur clique sur le bouton select_timezone_button
créé à l'étape 5.
Avant de définir la logique de rappel, il est utile de lier d'abord le bouton au nom de la méthode qui englobera éventuellement le code de rappel. La méthode bind()
peut être utilisée conjointement avec une fonction lambda
pour lier select_timezone_button
à la méthode de rappel spécifiée. Notez également que la fonction lambda
est utilisée pour transmettre des références aux widgets select_timezone_listbox
et time_label
en tant que paramètres de rappel. Ces paramètres de rappel ne sont en fait pas nécessaires puisque select_timezone_listbox
et time_label
sont dans la portée globale. Cependant, il est sans doute utile de montrer comment les arguments peuvent être passés à la fonction de rappel.
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) # Instance of Label widget class for selection prompt. select_timezone_label = tk.Label(root, text="Please select a timezone.") # Instance of Listbox class for selection of timezone from list. list_var = tk.Variable(value=timezones) select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1) # Instance of Button class to get the local time in the selected timezone. select_timezone_button = tk.Button(root, text="Get Time") # Second instance of the Label class to display the local time in the selected timezone. time_label = tk.Label(root, text="") # Place widgets on grid. select_timezone_label.grid(column=0, row=0, columnspan=4, sticky=tk.W, padx=10, pady=10) select_timezone_listbox.grid(column=0, row=1, columnspan=3, sticky=tk.EW, padx=10, pady=10) select_timezone_button.grid(column=4, row=1, sticky=tk.E, padx=10, pady=10) time_label.grid(column=0, row=4, columnspan=4, sticky=tk.W, padx=10, pady=10) select_timezone_button.bind("<Button>", lambda e, args=[select_timezone_listbox, time_label]: get_timezone_time(e, args))
La logique de rappel pour gérer les événements de clic de bouton est définie ci-dessous.
def get_timezone_time(e, args): select_timezone_listbox = args[0] time_label = args[1] selection_index = select_timezone_listbox.curselection() selected_timezone = select_timezone_listbox.get(selection_index) now_time = datetime.datetime.now() tz_time = now_time.astimezone(pytz.timezone(selected_timezone)) tz_formatted = tz_time.strftime("%H:%M:%S") time_label.configure({"text": f"The time in {selected_timezone} is {tz_formatted}."}) time_label.update()
Les curselection()
et get()
sont utilisées pour récupérer le fuseau horaire sélectionné par l'utilisateur à partir de la référence au widget select_timezone_listbox
. L'heure actuelle de l'utilisateur est ensuite convertie en l'heure du fuseau horaire sélectionné. Enfin, la méthode configure
est utilisée pour changer l'attribut text
de la référence en time_label
avec l'heure locale dans le fuseau horaire sélectionné. Notez que la méthode update()
est utilisée pour "forcer" le widget time_label
à se mettre à jour avec la nouvelle valeur de texte.
La méthode mainloop()
de la fenêtre racine est appliquée comme dernière ligne de code. La méthode mainloop()
exécutera l'interface graphique dans une boucle infinie jusqu'à ce que l'utilisateur quitte.
Le code complété est le suivant :
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] def get_timezone_time(e, args): select_timezone_listbox = args[0] time_label = args[1] selection_index = select_timezone_listbox.curselection() selected_timezone = select_timezone_listbox.get(selection_index) now_time = datetime.datetime.now() tz_time = now_time.astimezone(pytz.timezone(selected_timezone)) tz_formatted = tz_time.strftime("%H:%M:%S") time_label.configure({"text": f"The time in {selected_timezone} is {tz_formatted}."}) time_label.update() root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) # Instance of Label widget class for selection prompt. select_timezone_label = tk.Label(root, text="Please select a timezone.") # Instance of Listbox class for selection of timezone from list. list_var = tk.Variable(value=timezones) select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1) # Instance of Button class to get the local time in the selected timezone. select_timezone_button = tk.Button(root, text="Get Time") # Second instance of the Label class to display the local time in the selected timezone. time_label = tk.Label(root, text="") # Place widgets on grid. select_timezone_label.grid(column=0, row=0, columnspan=4, sticky=tk.W, padx=10, pady=10) select_timezone_listbox.grid(column=0, row=1, columnspan=3, sticky=tk.EW, padx=10, pady=10) select_timezone_button.grid(column=4, row=1, sticky=tk.E, padx=10, pady=10) time_label.grid(column=0, row=4, columnspan=4, sticky=tk.W, padx=10, pady=10) # Bind button to callback. select_timezone_button.bind("<Button>", lambda e, args=[select_timezone_listbox, time_label]: get_timezone_time(e, args)) root.mainloop()
Lorsque l'application est lancée, l'interface graphique devrait ressembler à :
Pour utiliser l'application, cliquez sur la zone de liste et utilisez les touches de curseur haut/bas de votre clavier pour faire défiler les options de fuseau horaire. Cliquez sur le bouton Obtenir l'heure pour afficher l'heure actuelle dans le fuseau horaire que vous avez sélectionné.
Félicitations pour la création de votre première application graphique Python avec Tkinter ! Comme mentionné dans l'introduction, ce guide a été conçu pour vous présenter quelques concepts de base. La documentation de la bibliothèque standard Python et les références de documentation des commandes Tk mentionnées précédemment sont deux ressources fantastiques pour vous aider à en savoir plus sur les fonctionnalités et fonctionnalités avancées de Tkinter.
Les applications Tkinter GUI sont parfois critiquées comme ayant une apparence non native. C'est peut-être vrai. Mais les widgets de la boîte à outils sont hautement configurables et les applications d'interface graphique Tkinter peuvent être créées relativement rapidement sans qu'il soit nécessaire d'installer des packages Python externes.
Au-delà de la documentation formelle, il existe d'innombrables didacticiels disponibles via Internet pour apprendre à créer des applications GUI plus sophistiquées avec Tkinter.