+++ title = "Tutoriel Tkinter Python" date = 2024-10-30 description = "Initiation aux interfaces graphiques" insert_anchor_links = "left" [taxonomies] tags = ["programmation", "Python"] +++ **Prérequis** : Il faut être un peu à l'aise avec le Python, au moins les variables, fonctions, manipulation des chaînes de caractères. Si ce n'est pas le cas, [France-IOI](https://www.france-ioi.org/algo/chapters.php) propose une introduction ludique au Python. Tkinter est une bibliothèque d'interface graphique, qui permet de créer des fenêtres sous Linux, Windows et Mac. C'est une des plus simples à utiliser en Python. Seulement elle est un peu vieille et trop peu intuitive, d'où ce tutoriel qui peut servir de mini-référence. Pour aller plus loin : [TkDocs Tutorial](https://tkdocs.com/tutorial/index.html) (en anglais) [Ce tutoriel est disponible en PDF.](/o/tuto/tkinter.pdf) Le code source et les commandes utilisées pour générer le PDF sont disponibles [dans ce dépôt Git](https://git.txmn.tk/tuxmain/jsb-editor). ## Code de base Créer une fenêtre vide : ```python import tkinter as tk from tkinter import ttk root = tk.Tk() root.mainloop() ``` Ajouter des boutons dans la fenêtre : ```python import tkinter as tk from tkinter import ttk root = tk.Tk() bt1 = ttk.Button(root, text="Bonjour") bt1.grid(column=0, row=0) bt2 = ttk.Button(root, text="Au revoir") bt2.grid(column=1, row=0) root.mainloop() ``` ### Positionnement On peut changer le nombre de colonnes ou de lignes occupées par un widget en ajoutant les paramètres `columnspan` ou `rowspan` en plus de `column` et `row`. Pour coller un widget au bord de la grille, on peut ajouter `sticky` : ```python bt2.grid(column=1, row=0, sticky=(tk.W, tk.N)) ``` `sticky` prend une liste de 0 à 4 éléments parmi : * `tk.E` : _East_ = droite * `tk.N` : _North_ = haut * `tk.S` : _South_ = bas * `tk.W` : _West_ = gauche ### Redimensionner la fenêtre Il faut indiquer quelles lignes et colonnes doivent changer de taille quand la fenêtre change de taille. Dans cet exemple, ce sont la ligne 1 et la colonne 0. ```python root.rowconfigure(1, weight=1) root.columnconfigure(0, weight=1) ``` On peut appeler plusieurs fois ces fonctions pour choisir plusieurs lignes et colonnes, et changer les `weight` pour modifier les proportions. ## Widgets Tous les widgets doivent être positionnés avec `grid`, de la même manière que ci-dessus. Sans ça, ils ne seront pas affichés ! ### Label Juste du texte. ```python label = ttk.Label(root, text="Je suis un texte. Wow.") ``` On peut aussi modifier le texte plus tard : ```python label_text = tk.StringVar() label["textvariable"] = label_text label_text.set("Le nouveau texte. Tout ça pour ça !") ``` ### Bouton Un bouton qu'on peut cliquer. ```python def onclick(): print("On a cliqué") bt = ttk.Button(root, text="Cliquez-moi", command=onclick) ``` ### Image Un bouton ou un label peut afficher une image : ```python img = tk.PhotoImage(file='image.png') label["image"] = img ``` ### Entrée de texte Boîte dans laquelle on peut écrire une ligne de texte. ```python text = tk.StringVar() entry = ttk.Entry(root, textvariable=text) ``` Plus tard, on peut récupérer le texte : ```python print("L'utilisateur a écrit :", text.get()) ``` ### Entrée de texte multiligne Zone dans laquelle on peut écrire du texte en plusieurs lignes. ```python text = tk.Text(root) ``` Il y a plusieurs méthodes pour interagir avec le texte : ```python print(text.get("1.0", "end")) # obtenir tout le texte print(text.get("2.0", "8.0")) # le texte de la ligne 2 à la ligne 8 text.replace("1.0", "end", "le nouveau texte") # remplacer du texte text.insert("1.0", "le nouveau texte") # insérer du texte text.insert("1.0 +42 chars", "le nouveau texte") text.insert("end -3 lines", "le nouveau texte") ``` Pour mettre en forme certaines parties du texte, on peut utiliser des tags : ```python text.tag_configure("fond_rouge", background="#ffaaaa") text.tag_configure("insistance", foreground="#008800", underline=True) text.insert("1.0", "ce texte sera sur fond rouge", "fond_rouge") text.tag_add("insistance", "1.3", "1.8") ``` [Liste de tous les styles possibles.](https://tcl.tk/man/tcl8.6/TkCmd/text.htm#M43) ### Barre de défilement Certains widgets (`Text`) peuvent défiler avec la molette, mais pour afficher la barre de défilement il faut un widget supplémentaire. ```python scroll = ttk.Scrollbar(root, orient=tk.VERTICAL, command=mon_widget_qui_défile.yview) scroll.grid(column=1, row=0, sticky=(tk.N, tk.S, tk.E, tk.W)) mon_widget_qui_défile.configure(yscrollcommand=scroll.set) ``` ### Cadre Un cadre qui peut avoir une bordure et contenir d'autres widgets. ```python frame = ttk.Frame(root, borderwidth=5, relief="ridge", width=200, height=100) ``` Les options ne sont pas obligatoires. Le cadre contient ses propres lignes et colonnes. Pour placer des widgets dedans, il suffit de remplacer `root` par `frame` en les créant. ### Barre de menus La barre de menus en haut de la fenêtre. ```python root.option_add('*tearOff', False) menubar = tk.Menu(root) root['menu'] = menubar menu_file = tk.Menu(menubar) menu_edit = tk.Menu(menubar) menubar.add_cascade(menu=menu_file, label='Fichier') menubar.add_cascade(menu=menu_edit, label='Édition') menu_file.add_command(label='Ouvrir', command=on_open) ``` ### Canevas Le canevas est une zone de dessin. ```python canvas = tk.Canvas(root, background='white') ``` On peut y dessiner des formes : ```python canvas.create_line(x1, y1, x2, y2) canvas.create_line(x1, y1, x2, y2, fill="red", width=3, dash=6) canvas.create_rectangle(x1, y1, x2, y2, fill="red", outline="blue") canvas.create_oval(x1, y1, x2, y2, fill="red", outline="blue") ``` ## Événements Quand il se passe quelque chose sur un widget, un événement est généré. On peut écouter les événements de certains types, c'est-à-dire lancer une fonction quand l'action se produit. Par exemple, on affiche des informations quand une touche du clavier est relâchée dans la zone de texte : ```python text = tk.Text(root) def onrelease(event): print("On a frappé le clavier !") print(event) text.bind("", onrelease) ``` On peut aussi utiliser les infos contenues dans l'événement, par exemple `event.keycode`. ### Liste des événements * Souris * `ButtonPress`: clic enfoncé d'un bouton de la souris * `Button-1`: comme `ButtonPress` mais seulement pour le clic gauche * `Button-2`: comme `ButtonPress` mais seulement pour le clic molette * `Button-3`: comme `ButtonPress` mais seulement pour le clic droit * `ButtonRelease`: clic relâché d'un bouton de la souris * `Double-1`: double-clic gauche * `Double-3`: double-clic droit * `Enter`: le pointeur de la souris entre * `Leave`: le pointeur de la souris sort * `Motion`: le pointeur de la souris bouge dedans * `B1-Motion`: comme `Motion` mais avec le clic gauche enfoncé * `B2-Motion`: comme `Motion` mais avec le clic molette enfoncé * `B3-Motion`: comme `Motion` mais avec le clic droit enfoncé * Clavier * `KeyPress`: appui d'une touche du clavier * `KeyRelease`: relâche d'une touche du clavier * Widget * `Configure`: le widget est créé * `Expose`: le widget est affiché ou réaffiché * `FocusIn`: le widget reçoit le focus * `FocusOut`: le widget pert le focus ## Dialogues On peut ouvrir des fenêtres pour dire ou demander des choses. ### Fichiers Demander où enregistrer un fichier, quel fichier ouvrir, choisir un dossier. ```python from tkinter import filedialog filetypes = [ ("Texte", "*.txt"), ("Image PNG", "*.png"), ("Autre", "*.*") ] chemin = tk.filedialog.asksaveasfilename(filetypes=filetypes) print(chemin) ``` On peut remplacer `asksaveasfilename` par `askopenfilename` ou `askdirectory`. ### Couleur Demander de choisir une couleur. ```python from tkinter import colorchooser color = colorchooser.askcolor(initialcolor='black') print(color) ``` On peut aussi indiquer la couleur initiale avec sa notation hexadécimale `"#000000"`.