Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Interfaces utilisateur graphiques

Make code user-friendly. For interactive reading and executing code blocks Binder and find b10-gui.ipynb, or install Python and JupyterLab locally.

Une interface utilisateur graphique (GUI) facilite la configuration des variables d’entrée des scripts. Ceci est particulièrement utile pour réutiliser un script que vous avez écrit il y a longtemps, sans avoir à étudier l’ensemble du script en détail. Bien que l’on puisse se demander si les IGU sont toujours appropriés en période d’applications Web, les données importantes et en particulier les données protégées par le droit d’auteur doivent être traitées localement. En fin de compte, pour le traitement des données locales, une interface graphique peut être très pratique pour exécuter des programmes auto-écrits et personnalisés.

Plusieurs bibliothèques GUI (paquets) sont disponibles pour Python et ce chapitre s’appuie sur la bibliothèque tkinter. Les alternatives sont, par exemple, wxPython ou Jython (une implémentation Java de Python2). tkinter est une bibliothèque standard, qui n’a pas besoin d’être installée en plus. Pour un exemple rapide, tapez dans le terminal (p. ex. Anaconda Prompt, PyCharm ou Linux terminal - pas dans Python lui-même):

python -m tkinter

tkinter travaille sur les plateformes les plus populaires (Linux, macOS, Windows) et est non seulement disponible à Python, mais aussi Ruby, Perl, Tcl (l’origine de tkinter), et beaucoup d’autres langues. Parce qu’il prend en charge des langages comme Ruby ou Perl, tkinter peuvent être utilisés pour les GUI locaux ainsi que pour les applications web.

Le premier GUI

La première étape est import tkinter, en utilisant habituellement le pseudo as tk. Avec tk.Tk(), une fenêtre dite parent (par exemple, top) peut être créée, dans laquelle d’autres éléments seront pris en compte. Tous les autres éléments sont créés sous la forme de tk enfants objets de la fenêtre parent et placés (disposés) dans la fenêtre parent en utilisant la méthode pack() ou grid(). Ici, nous utiliserons pack la plupart du temps et grid sera utile pour placer des éléments à une position exacte sur la fenêtre (par exemple, tk.ELEMENT.grid(row=INT, column=INT)). Pour afficher l’interface graphique, la fenêtre principale top doit être lancée avec top.mainloop() après avoir organisé tous les éléments. Le bloc de code suivant montre comment créer une fenêtre parent avec un élément d’étiquette (tk.Label).

import tkinter as tk
top = tk.Tk()
a_label = tk.Label(top, text = "A label just shows some text.")
a_label.pack()
top.mainloop()
python GUI tkinter

Figure 1:L’interface utilisateur.

Après avoir appelé la méthode mainloop() la fenêtre est dans un état attendre. Cela signifie que la fenêtre attend que events soit déclenchée par l’action de l’utilisateur (par exemple, un clic sur un bouton). Ceci est appelé event-drived programming, où event handlers sont appelés plutôt qu’un flux linéaire unique sous la forme d’une séquence de commandes (Python).

Pour l’instant, notre fenêtre utilise des valeurs par défaut, par exemple, pour le titre, la taille et la couleur de fond de la fenêtre. Ces propriétés de la fenêtre peuvent être modifiées avec les attributs title, minsize ou maxsize et configure de la fenêtre principale top:

top = tk.Tk()
a_label = tk.Label(top, text="A label just shows some text.")
a_label.pack()

top.title("My first GUI App")
top.minsize(628, 382)
top.configure(bg="sky blue")
top.mainloop()
python GUI tkinter with label config

Figure 2:L’interface graphique configurée.

Ajouter un bouton pour appeler une fonction

Actuellement, la fenêtre n’affiche qu’un label (boring) et attend des événements qui n’existent pas. Avec un tk.Button nous pouvons ajouter un déclencheur d’événement, qui a encore besoin de quelque chose à déclencher. À cette fin, définir une fonction call_back qui crée une infobox, qui est un objet de showinfo de tkinter.messagebox (i.e., il doit être importé).

from tkinter.messagebox import showinfo
# more message boxes: askokcancel, askyesno

def call_back(message):
    showinfo("This is an Infobox", message)


top = tk.Tk()
a_label = tk.Label(top, text="Here is the button.")
a_label.pack()
# add a button
a_button = tk.Button(top, text = ">> Click <<", command=lambda: call_back("Greetings from the Button."))
a_button.pack()
top.mainloop()
python GUI tkinter with button

Figure 3:L’interface graphique avec un bouton appelant une boîte d’info.

Programme Vanilla tkinter

Le code ci-dessus bloque instantanée tkinter objets (widgets) dans un style de script non orienté objet. Cependant, lorsque nous écrivons une interface graphique, nous voulons probablement lancer une application (App) en exécutant le script. C’est pourquoi tkinter widgets sont généralement créés comme des objets de classes personnalisées qui héritent généralement de tk.Frame. Par conséquent, le bloc de code suivant transforme l’exemple précédent en un code orienté objet avec le modèle de section on Python classes.

L’exemple ci-dessous crée un cadre VanillaApp, qui est un enfant de tk.Frame (tkinters master). La méthode d’initialisation __init__ doit invoquer tk.Frame et pack() elle pour initialiser la fenêtre. Après cela, nous pouvons placer d’autres widgets comme des étiquettes et des boutons comme avant. Dans le VanillaApp, nous pouvons également implémenter directement la fonction call_back ci-dessus comme une méthode. En outre, faire tourner le script autonome (non soutenu par un beau carnet Jupyter) en ajoutant une déclaration if __name__ == "__main__": VanillaApp().mainloop() au bas du script (lire plus sur la déclaration __main__ dans le section on packages).

# define the VanillaApp class
class VanillaApp(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.pack()
        
        table_label = tk.Label(master, text="Do you want vanilla ice?")
        table_label.pack()
        vanilla_button = tk.Button(master, text = "I want Vanilla", command=lambda: call_back("Here is Vanilla!"))
        vanilla_button.pack()
        no_vanilla_button = tk.Button(master, text = "I want something else", command=lambda: call_back("Here is bread!"))
        no_vanilla_button.pack()
        
    def call_back(self, message):
        showinfo("This is an Infobox", message)


# instantiate a VanillaApp object
if __name__ == "__main__":
    VanillaApp().mainloop()
python GUI tkinter vanilla label button

Figure 4:La VanillaApp GUI avec deux boutons et une étiquette.

Faites du script une application autonome

Le bloc de code ci-dessus fournissant la classe VanillaApp peut être copié dans n’importe quel fichier Python externe et enregistré comme, par exemple, vanilla_app.py. Ensuite, dans Anaconda Prompt (Windows) ou Linux Terminal démarre l’interface graphique comme suit (selon le Python installation utilisé):

  1. Activer l’environnement requis, par exemple:

    • Windows/Anaconda: conda activate flussenv

    • Linux/Virtualenv: source vflussenv/bin/activate

  2. Naviguez dans le répertoire où se trouve le script (utilisez cd à Windows ou Linux/macOS).

  3. Tapez python vanilla_app.py (ou python -m vanilla_app.py) pour lancer l’interface graphique.

Cette séquence de commandes peut également être écrite dans un fichier batch ou bash (.bat on Windows) ou shell script (.sh on Linux/macOS - alternative documentation). Après avoir écrit et enregistré un fichier batch ou bash, double-cliquez sur le fichier pour démarrer l’interface graphique basée sur Python.

Autres widgets

Il y a beaucoup plus de widgets que les étiquettes et les boutons et la figure ci-dessous comporte certains d’entre eux, y compris:

  • Une définition du nom de la fenêtre GUI avec master.title("Window name")

  • Une définition de l’icône de fenêtre GUI (ICO) avec master.iconbitmap("directory/icon-file.ico")

  • tk.Menu avec cascade déroulante

  • tk.Label (voir plus haut)

  • tk.Button (voir plus haut)

  • tk.Entry qui est un champ vide où les utilisateurs peuvent saisir des valeurs ou des mots

  • ttk.Combobox qui est un menu déroulant dans le cadre principal (tk-themed ttk widget)

  • tk.Listbox avec un tk.Scrollbar, où la barre de défilement est nécessaire pour naviguer vers des entrées de listbox qui ne sont pas dans la plage visible de la taille de listbox

  • tk.Checkbutton that can be checked (ticked) to set a tk.BooleanVar() object to True (default: not checked -> False)
    Alternatively, have a look at tk.Radiobutton to enable selections from a multiple-choice frame (rather than the False-True-only frame of a checkbutton)

  • tk.PhotoImage pour afficher une image sous-échantillonnée dans l’interface graphique

python GUI tkinter with widgets entry combobox listbox checkbutton radiobutton photo image

Figure 5:GUI avec plusieurs widgets, tels que Menu, Label, Bouton, Entrée, Combobox, Listbox, Checkbutton et PhotoImage.

Le prochain bloc comporte le code qui crée les widgets tkinter dans la figure (les script, image et icon sont disponibles au dépôt de cours):

import tkinter as tk
from tkinter.messagebox import showinfo
from tkinter import ttk


class MyApp(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)

        self.master.title("Master Title")
        self.master.iconbitmap("gui/sample-icon.ico")

        # Set geometry: upper-left corner of the window
        ww = 628  # width
        wh = 382  # height
        wx = (self.master.winfo_screenwidth() - ww) / 2
        wy = (self.master.winfo_screenheight() - wh) / 2
        # assign geometry
        self.master.geometry("%dx%d+%d+%d" % (ww, wh, wx, wy))
        # assign space holders around widgets
        self.dx = 5
        self.dy = 5

        # Menu Bar
        self.mbar = tk.Menu(self)  # create standard menu bar
        self.master.config(menu=self.mbar)  # make self.mbar standard menu bar
        # add menu entry
        self.ddmenu = tk.Menu(self, tearoff=0)
        self.mbar.add_cascade(label="A Drop Down Menu", menu=self.ddmenu)  # attach entry it to standard menu bar
        self.ddmenu.add_command(label="Drop Down Entry 1", command=lambda: self.hello("Drop Down Menu!"))

        # Label
        self.a_label = tk.Label(master, text="A Label")
        self.a_label.grid(column=0, row=0, padx=self.dx, pady=self.dy)

        # Button
        self.a_button = tk.Button(master, text="A Button", command=lambda: self.hello("The Button!"))
        self.a_button.grid(column=0, row=1, padx=self.dx, pady=self.dy)

        # Entry
        self.an_entry = tk.Entry(master, width=20)
        self.an_entry.grid(column=0, row=2, padx=self.dx, pady=self.dy)

        # Combobox
        self.cbox = ttk.Combobox(master, width=20)
        self.cbox.grid(column=0, row=3, padx=self.dx, pady=self.dy)
        self.cbox['state'] = 'readonly'
        self.cbox['values'] = ["Combobox Entry 1", "Combobox Entry 2", "Combobox Entry ..."]
        self.cbox.set("Combobox Entry 1")
        self.cbox_selection = self.cbox.get()

        # Listbox with Scrollbar
        self.scrlbar = tk.Scrollbar(master, orient=tk.VERTICAL)
        self.scrlbar.grid(sticky=tk.W, column=1, row=4, padx=self.dx, pady=self.dy)
        self.lbox = tk.Listbox(master, height=3, width=20, yscrollcommand=self.scrlbar.set)
        for e in ["Listbox Entry 1", "Listbox Entry 2", "With Scrollbar ->", "lb entry n"]:
            self.lbox.insert(tk.END, e)
        self.lbox.grid(sticky=tk.E, column=0, row=4, padx=self.dx, pady=self.dy)
        self.scrlbar.config(command=self.lbox.yview)
        self.lbox_selection = self.lbox.get(0)

        # Checkbutton
        self.check_variable = tk.BooleanVar()
        self.cbutton = tk.Checkbutton(master, text="Tick this Checkbutton", variable=self.check_variable)
        self.cbutton.grid(sticky=tk.E, column=2, row=0, padx=self.dx, pady=self.dy)

        # Image
        logo = tk.PhotoImage(file="gui/sunny-image.gif")
        logo = logo.subsample(2, 2)  # controls size
        self.l_img = tk.Label(master, image=logo)
        self.l_img.image = logo
        self.l_img.grid(row=1, column=2, rowspan=4)
        # create a placeholder to relax layout
        tk.Label(text="                                                    ").grid(row=0, column=1)
        
    @staticmethod
    def hello(message):
        showinfo("Got Message from ...", message)


if __name__ == '__main__':
    MyApp().mainloop()

Il y a beaucoup d’autres options (widgets) disponibles et TkDocs fournit un aperçu détaillé et moderne des objets disponibles tkinter.

tkinter Variables

Dans l’exemple ci-dessus, la case reçoit un tk.BooleanVar(), qui prend une valeur True quand un utilisateur vérifie la case. Il existe d’autres variables qui peuvent être associées à tkinter widgets (p. ex., tk.Entry, tk.Listbox, ou ttk.Combobox). Les variables tkinter correspondent essentiellement à Python data types avec des méthodes spéciales qui sont nécessaires pour définir ou récupérer des valeurs définies par l’utilisateur de ces types de données. Voici un aperçu des variables tkinter:

  • tk.BooleanVar() est un boolean qui peut être True ou False

  • tk.DoubleVar() est une variable numérique flottante (float)

  • tk.IntVar() est une variable numérique integer

  • tk.StringVar() est un string (c’est-à-dire généralement du texte)

Comment Python sait-il quand récupérer une valeur définie par l’utilisateur ? Généralement, nous voulons évaluer les valeurs définies par l’utilisateur lorsque nous appelons une fonction qui reçoit des valeurs définies par l’utilisateur comme arguments d’entrée. Les valeurs par défaut prédéfinies dans un script peuvent être définies avec VARIABLE.set() et les paramètres de l’utilisateur peuvent être récupérés avec VARIABLE.get(). Les documents suivants script et icon] sont disponibles au dépôt des cours.

from tkinter.messagebox import showinfo
import random

class MyApp(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)

        self.master.title("GUI with variables")
        self.master.iconbitmap("gui/sample-icon.ico")

        # Set geometry: upper-left corner of the window
        ww = 628  # width
        wh = 100  # height
        wx = (self.master.winfo_screenwidth() - ww) / 2
        wy = (self.master.winfo_screenheight() - wh) / 2
        # assign geometry
        self.master.geometry("%dx%d+%d+%d" % (ww, wh, wx, wy))

        self.a_label = tk.Label(master, text="Enter a value to call:")
        self.a_label.grid(column=0, row=0, padx=5, pady=5)
        
        # define tk.StringVar() and assign it to an entry
        self.user_entry = tk.StringVar()
        self.an_entry = tk.Entry(master, width=20, textvariable=self.user_entry)
        self.an_entry.grid(column=1, row=0, padx=5, pady=5)

        # define Button to trigger call back
        self.a_button = tk.Button(master, text="Call Message!", command=lambda: self.message_distributor())
        self.a_button.grid(column=2, row=0, padx=5, pady=5)

        # define a Checkbutton to use either user input or a random message
        self.check_variable = tk.BooleanVar()
        self.cbutton = tk.Checkbutton(master, text="Check this box to use a random message instead of the entry", variable=self.check_variable)
        self.cbutton.grid(sticky=tk.E, column=0, columnspan=3, row=1, padx=5, pady=5)
        self.check_variable.set(False)

        
    def message_distributor(self):
        if not self.check_variable.get():
            showinfo("User message", self.user_entry.get())
        else:
            showinfo("Random message", self.random_message())
        
    def random_message(self):
        random_words = ["summer", "winter", "is", "cold", "hot", "will be"]
        return " ".join(random.sample(random_words, 3))


if __name__ == '__main__':
    MyApp().mainloop()
python GUI tkinter bound to variables

Figure 6:L’interface graphique est liée aux variables Tk.

Conception, emplacement et modification des widgets

Les exemples de code ci-dessus utilisent à la fois les méthodes OBJECT.grid() et OBJECT.pack() (gestionnaires de géométrie) pour placer des widgets dans l’interface graphique. Il y a un gestionnaire de géométrie supplémentaire sous la forme de la méthode place. Le choix d’un gestionnaire de géométrie pratique dépend de vos préférences et il y a des avantages et des inconvénients pour les trois gestionnaires de géométrie:

  • pack

    • place automatiquement les widgets dans une boîte

    • fonctionne mieux pour les interfaces graphiques simples, où tous les widgets sont dans une colonne ou une ligne

    • les mises en page complexes ne peuvent être gérées que par des solutions de rechange compliquées (conseil : ne pas essayer)

  • place

    • place des widgets à des positions absolues ou relatives x-y

    • fonctionne bien pour les arrangements graphiques des widgets

  • grid

    • place les widgets dans les colonnes et les lignes d’une grille

    • fonctionne bien avec les applications de table et les mises en page structurées

Pour permettre une plus grande flexibilité graphique, les widgets acceptent plusieurs mots clés optionnels pour changer leur couleur de premier plan (fg) ou de fond (bg). De plus, les widgets peuvent être modifiés avec la méthode tk.OBJECT.config(PARAMETER_TO_CONFIGURE=NEW_CONFIG).

Les sections suivantes fournissent plus de détails sur les gestionnaires de géométrie place et grid (les fonctions pertinentes de pack sont déjà indiquées ci-dessus: pack() - c’est tout) et illustrent les arguments de mots clés ainsi que les méthodes de widget pour modifier les widgets.

Placez place et utilisez les couleurs d’objet

Le gestionnaire de géométrie le plus simple est la méthode pack, qui fonctionne même sans aucun mot-clé fourni (voir les tout premiers exemples dans cette section). Avec la méthode pack, les widgets peuvent être placés relativement dans la fenêtre (relx et rely, où les deux doivent être < 1) ou avec des positions absolues (x et y, où les deux doivent s’insérer dans les dimensions de la fenêtre définies par self.config(width=INT, height=INT)). L’origine de l’axe (position zéro de x et y) est déterminée avec le mot clé anchor.

class PlacedApp(tk.Frame):
    def __init__(self, master=None, **options):
        tk.Frame.__init__(self, master, **options)
        self.pack(expand=True, fill=tk.BOTH)
        self.config(width=628, height=100)
        self.master.title("A placed GUI")
        tk.Label(self, text="Vanilla", bg="goldenrod", fg="dark slate gray").place(anchor=tk.NW, relx=0.2, y=10)
        tk.Label(self, text="Green green tree", bg="OliveDrab1").place(anchor=tk.E, relx=0.8, rely=0.5)
        tk.Label(self, text="Blue sky", bg="DeepSkyBlue4", fg="floral white").place(anchor=tk.CENTER, x=300, rely=0.8)


if __name__ == '__main__':
    PlacedApp().mainloop()
python GUI tkinter using placed

Figure 7:L’interface graphique est organisée avec des widgets placés.

Placer les objets avec grid

Dans grid-ed GUI, l’alignement du widget peut être contrôlé avec l’argument sticky qui utilise des directions cardinales (par exemple, sticky=tk.W aligne ou “colle” un widget à l’ouest, ce qui signifie, côté gauche, d’un GUI). Les arguments padx et pady mots-clés permettent l’implémentation de l’espace pixel autour des widgets.

from tkinter.messagebox import showinfo

class GriddedApp(tk.Frame):
    def __init__(self, master=None, **options):
        tk.Frame.__init__(self, master, **options)
        self.pack(expand=True, fill=tk.BOTH)
        self.config(width=628, height=100)
        self.master.title("A grid GUI")
        tk.Label(self, text="Enter name: ", bg="bisque2", fg="gray21").grid(sticky=tk.W, row=0, column=0, padx=10)
        tk.Entry(self, bg="gray76", width=20).grid(sticky=tk.EW, row=0, column=1, padx=5)
        tk.Button(self, text="Show message", bg="pale turquoise", fg="red4", command=lambda: showinfo("Info", "Random message")).grid(row=0, column=2, padx=5)
        tk.Checkbutton(self, text="A Checkbutton over multiple columns").grid(sticky=tk.E, row=1, column=0, columnspan=3, pady=15)


if __name__ == '__main__':
    GriddedApp().mainloop()
python GUI tkinter structured as grid

Figure 8:L’interface utilisateur organisée sur une grille.

Configurer les widgets

Lors de l’action de l’utilisateur (un événement), nous pourrions vouloir modifier des widgets précédemment définis. Par exemple, nous pouvons vouloir modifier le texte d’une étiquette ou la disposition d’un bouton pour indiquer les opérations réussies ou échouées. À cette fin, les objets tkinter peuvent être modifiés avec tk.OBJECT.config(PARAMETER_TO_CONFIGURE=NEW_CONFIG). En outre, les objets peuvent être supprimés (détruites) avec tk.OBJECT.destroy(), même si ce n’est pas une méthode élégante pour d’autres widgets que les fenêtres pop-up (cadres pour enfants du cadre principal).

from tkinter.messagebox import showinfo, showerror

class ReConfigApp(tk.Frame):
    def __init__(self, master=None, **options):
        tk.Frame.__init__(self, master, **options)
        self.config(width=628, height=100)
        self.pack()
        
        self.user_depth = tk.DoubleVar()
        self.kst = 40.0
        self.w = 5.0
        self.slope = 0.002
        
        self.master.title("A GUI that reconfigures its widgets")
        tk.Label(self, text="Enter flow depth (numeric, in meters): ", bg="powder blue", fg="medium blue").grid(sticky=tk.W, row=0, column=0, padx=10)
        tk.Entry(self, bg="alice blue", width=20, textvariable=self.user_depth).grid(sticky=tk.EW, row=0, column=1, padx=5)
        self.eval_button = tk.Button(self, text="Estimate flow velocity", bg="snow2", fg="dark violet", command=lambda: self.call_estimator())
        self.eval_button.grid(row=0, column=2, padx=5)
        
    def call_estimator(self):
        try:
            flow_depth = float(self.user_depth.get())
        except tk.TclError:
            return showerror("ERROR", "Non-numeric value entered.")
        self.eval_button.config(fg="green4", bg="DarkSeaGreen1")
        showinfo("Result", "The estimated flow velocity is: " + str(self.estimate_u(flow_depth)))
        
    def estimate_u(self, h):
        try:
            return self.kst * h**(2/3) * self.slope**0.5
        except ValueError:
            showerror("ERROR: Bad values defined.")
            return None
        except TypeError:
            showerror("ERROR: Bad data types defined.")
            return None
        

if __name__ == '__main__':
    ReConfigApp().mainloop()
python GUI tkinter re-configured

Figure 9:L’interface graphique reconfigurée.

Fenêtres contextuelles

Messages par défaut de tkinter.messagebox

La bibliothèque tkinter.messagebox fournit des fenêtres pop-up standard, comme:

  • showinfo(title=STR, message=STR) qui imprime un message d’information (voir exemples ci-dessus).

  • showwarning(title=STR, message=STR) qui imprime un message d’avertissement.

  • showerror(title=STR, message=STR) qui imprime un message d’erreur (voir l’exemple ci-dessus).

  • askyesno(title=STR, message=STR) qui retourne False ou True selon les réponses d’un utilisateur à une question Oui-ou-Non.

  • askretrycancel(title=STR, message=STR) qui retourne False ou True, ou ré-attente pour exécuter un événement (fonction) selon les réponses d’un utilisateur à une question Oui-ou-Non-ou-Annuler.

  • askokcancel(title=STR, message=STR) qui retourne False ou True selon les réponses d’un utilisateur à une question OK.

En savoir plus sur les fenêtres pop-up par défaut dans le Python docs.

Pop-ups personnalisées de haut niveau

Les fenêtres par défaut peuvent ne pas répondre aux besoins de chaque application, par exemple, pour inviter les utilisateurs à entrer une valeur personnalisée. Dans ce cas, un objet tk.Toplevel aide à produire une fenêtre pop-up personnalisée, et l’exemple ci-dessous montre comment une fenêtre pop-up de haut niveau personnalisée peut être appelée dans une méthode. Avec le widget tk.Toplevel et les widgets tk.Frame (master), le bloc de code produit deux cadres dans lesquels des boutons, des étiquettes ou tout autre objet tkinter peuvent être placés. Le tout premier argument de tout tkinter widget-objet créé détermine si l’objet est placé dans le maître ou le cadre de haut niveau. Par exemple, tk.Entry(self).pack() crée une entrée dans le maître tk.Frame, et tk.Entry(pop_up).pack() crée une entrée dans l’enfant tk.Toplevel.

from tkinter.messagebox import showwarning

class PopApp(tk.Frame):
    def __init__(self, master=None, **options):
        tk.Frame.__init__(self, master, **options)
        self.config(width=628, height=50)
        self.pack()
        
        self.master.title("Custom pop-up GUI")
        self.pop_button = tk.Button(self, text="Open pop-up window", bg="cadet blue", fg="white smoke", command=lambda: self.new_window())
        self.pop_button.pack()
        
    def destroy_buttons(self):
        self.pop_button.destroy()
        self.p_button1.destroy()
        self.p_button2.destroy()        
        showwarning("Congratulations", "This app is useless now. Don't press red-ish buttons ...")
        
    def new_window(self):
        pop_up = tk.Toplevel(master=self)
        # add two buttons to the new pop_up Toplevel object (window)
        self.p_button1 = tk.Button(pop_up, text="Destroy buttons (do not click here)", fg="DarkOrchid4",
                                   bg="HotPink1", command=lambda: self.destroy_buttons())
        self.p_button2 = tk.Button(pop_up, text="Close window", command=lambda: pop_up.quit())  
        self.p_button1.pack()
        self.p_button2.pack()


if __name__ == '__main__':
    PopApp().mainloop()
python tkinter popup window customized

Figure 11:L’interface graphique avec fenêtre contextuelle personnalisée.

Boîte de dialogue de fichier (Ouvrir ...)

When a custom function’s argument is a file or file name, we most likely want the user to be able to select the file type needed. The tkinter.filedialog library provides methods to let users choose general or specific file types. Specific file types can be defined with the filetypes=("Name", "*.ending") (or filetypes=("Name", "*.ending1;*.ending2;...") for multiple file types) keyword argument. The following example illustrates the usage of tkinter.filedialog’s askopenfilename.

from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showinfo

class OpenFileApp(tk.Frame):
    def __init__(self, master=None, **options):
        tk.Frame.__init__(self, master, **options)
        self.config(width=628, height=50)
        self.pack()
        
        self.master.title("GUI to open a file")
        
        self.pop_button = tk.Button(self, text="Open a text file", bg="light steel blue", fg="dark slate gray", command=lambda: self.open_file())
        self.pop_button.pack()
        
    def open_file(self):
        file_types = (("Text", "*.txt;*.csv;*.asc"),)  # equivalent to [("Text", "*.txt;*.csv;*.asc")]
        file_name = askopenfilename(initialdir=".", title="Select a text file", filetypes=file_types, parent=self)
        showinfo("File info", "You selected " + str(file_name))


if __name__ == '__main__':
    OpenFileApp().mainloop()
python tkinter with filedialog

Figure 12:L’interface graphique avec filedialog pour sélectionner un fichier.

Quitter

Pour quitter complètement une interface graphique, utilisez tk.Frame.quit() (i.e., dans une classe personnalisée, écrivez self.quit() ou master.quit()). L’exemple ci-dessus de la classe PopApp comporte également la méthode destroy(), qui aide à supprimer des widgets particuliers.

tkinter offre beaucoup d’autres options telles que l’implémentation d’onglets avec ttk.Notebook() (requiert reliant des objets de l’onglet), des tables (from tkintertable import TableCanvas, TableModel), ou des objets graphiques interactifs avec matplotib.

import matplotlib
matplotlib.use('TkAgg')
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

Profitez de la création de vos applications personnalisées!

Vérification de la réussite en apprentissage

Prenez le test de réussite d’apprentissage pour ce carnet Jupyter.