diff --git a/content/blog/tkinter.fr.md b/content/blog/tkinter.fr.md new file mode 100644 index 0000000..6638850 --- /dev/null +++ b/content/blog/tkinter.fr.md @@ -0,0 +1,305 @@ ++++ +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"`.