Networking en Python
TkInter est une bibliothèque Python utilisée pour la mise en place d'interfaces graphiques sous Python. C'est une bibliothèque qui existe nativement dans le langage et qui ne nécessite pas d'autre chose à faire que de l'importer pour l'utiliser. Elle est relativement ancienne, pas toujours très jolie mais a le mérite d'exister en proposant une syntaxe relativement simple et immédiate avec des fonctionnalités étendues.
Comme dans les lignes qui suivent il n'est pas prévu de retranscrire une documentation complète, je vous laisse consulter la notice de tkInter disponible sur les pages du New Mexico Tech Computer Center qui, bien que plus tenue à jour depuis des années n'en reste pas moins une excellente source d'informations.
Chaque widget graphique dispose d'éléments communs tels que :
from tkinter import Tk, font
root = Tk() # instancier un objet de tkinter pour ouvrir la classe tkInter
print(font.names()) # affiche les polices disponibles sur le système
print(font.families()) # affiche les polices de caractères utilisables sur l'environnement de votre machine
et ensuite définir des options :
La bibliothèque tkInter fonctionne par événements, comme n'importe laquelle des interfaces modernes dignes de ce nom. Une boucle principale se chargera d'attendre les événements et réagira en fonction de ceux-ci. Le fenêtre principale est vierge avec une taille par défaut et sans titre ni icone. Tous les éléments d'interface qui seront disposés sur cette fenêtre disposent d'options (police, couleur, texte...) qui sont déclarés en tant que paramètre à la création de l'objet (text="texte à afficher", width=50, ...). Durant l'exécution du programme, les valeurs des objets peuvent être lues (méthode .cget()) ou bien redéfinies (méthode .config()).
import tkinter as tk
mainwin = tk.Tk() # instancie un objet tkinter (l'objet de base est une fenêtre invisible)
mainwin.title("Première fenêtre") # affecte un titre à la fenêtre
mainwin.geometry("800x600") # redimensionne la fenêtre pour le premier affichage
mainwin.minsize(640, 480) # définit la taille minimal de la fenêtre
mainwin.maxsize(1024, 768) # définit la taille maximale de la fenêtre
mainwin.resizable(width=False, height=True) # autorise le redimensionnement horizontal uniquement
mainwin.mainloop() # entre dans la boucle des événements, affiche la fenêtre et attend les événements
Les objets disposent de propriétés permettant notamment des récupérer des dimensions.
# Récupère les dimensions de l'écran
screen_width = mainwin.winfo_screenwidth()
screen_height = mainwin.winfo_screenheight()
# Centrage de la fenêtre
geo = "{}x{}+{}+{}".format("800", "600", screen_width, screen_height)
mainwin.geometry(geo)
TkInter dispose d'un grand nombre de widgets (window gadgets) qui vont permettre de réaliser des menus, des listes, des labels, des zones
de saisie...tout ce qui donne un aspect moderne à une interface graphique. Les widgets sont créés globalement tous avec le même type
d'appel à savoir nom_variable = nom_widget(widget_parent, paramètres...)
. Une fois le label créé, il n'est pas nativement affiché.
Il faut forcer l'affichage en spécifiant un gestionnaire de géométrie. Sous ce terme barbare sont regroupés les façons qu'à tkinter de
placer les widgets dans l'interface. Il existe un mode statique/absolu où les widgets sont positionnés au pixel près mais ne peuvent pas
s'adapter lors du redimensionnement, ou bien un agencement dynamique qui prendra la forme de boîtes horizontales ou verticales, de grilles
ou de package d'un widget par ligne. Nous les verrons au fur et à mesure.
Les widgets créés ne sont pas figés dans le marbre. Il existe la méthode .configure(params...) ou son alias .config(option) qui permet de modifier ou d'ajouter des attributs à un widget lorsqu'il existe déjà.
Pour lire la valeur d'un attribut d'un widget, il faut utiliser la méthode .cget("attribut"). Le nom de l'attribut est à écrire entre guillemets.
Les options génériques principales des widgets sont les suivantes :
bg ou background | La couleur de fond du widget. Cette couleur est généralement gris clair |
bd ou borderwidth | La largeur de la bordure entourant le widget. Deux pixels généralement par défaut. |
fg ou foreground | La couleur de premier plan de rendu du widget. Par défaut la couleur noire est utilisée. |
Le label est l'élément le plus simple de l'interface et dont le rôle se contente à afficher de l'information au format texte. Pour le faire afficher, il doit être mis dans les mains d'un gestionnaire de positionnement. Nous choisissons le plus simple ici car l'objectif est de faire afficher les widgets, pas d'en faire une interface utilisateur utilisable. Le gestionnaire utilisé est pack() qui permet de positionner les widgets les uns en dessous des autres automatiquement centrés.
Pour saisir une donnée sur une seule ligne, le widget est Entry. Par défaut, sa dimension est de 20 caractères de largeur affichés, mais sans limite réelle du champ de saisie. Les options spécifiques (liste non exhaustive) :
exportselection (bool) | Par défaut, la sélection faite dans un champ de saisie est stockée dans le presse papier automatiquement. Pour désactiver ce comportement, mettez exportselection=0 dans les options du champ. |
show | Si vous voulez afficher un caractère générique à la place de celui saisi (comme un champ de mot de passe par exemple), spécifiez l'option show='*'. |
width | La taille en caractères du champ de saisie. Par défaut de 20 caractères. |
Permet la création d'un simple bouton sur l'interface. Ses options sont les suivantes :
bitmap | L'image au format bitmap à afficher à la place du texte. |
command | La fonction devant être appelée lors de l'appui sur le bouton command=fonction. La référence à la fonction n'inclut pas les parenthèses. |
height | La hauteur en lignes de caractères ou en pixels selon l'objet affiché par le bouton. |
image | L'image à afficher à la place du texte par défaut. |
text | Le texte qui sera affiché dans le bouton. |
width | La largeur du bouton en nombre de caractères si l'affichage contient du texte ou en pixel si le bouton affiche une image. |
Tkinter nous offre 3 méthodes générales pour afficher des images :
from PIL import ImageTk, Image
img = ImageTk.PhotoImage(Image.open('image.png'))
import tkinter as tk
mainwin = tk.Tk()
# Crée un label avec un texte
hello = tk.Label(mainwin, text="Hello World")
hello.pack()
# Création d'un label et affectation d'un attribut ultérieur
hello2 = tk.Label(mainwin)
hello2.configure(text="Hello encore")
hello2.pack()
# Affiche sur la console la valeur de l'attribut text du widget label hello2
print(hello2.cget("text"))
mainwin.mainloop()
Parmi les widget considérés comme avancés on retrouve les cases à cocher, les radio boutons, les listes, les boites de messages, les sliders, les spinbox... En voici quelques éléments utiles.
Un checkbutton est une simple case à cocher qui permet de valider ou non une option. S'il y a plusieurs cases à cocher sur l'interface, celles-ci sont
toutes mutuellement indépendantes par défaut. Chaque checkbox dispose d'une variable distincte des autres.
Un radiobutton est l'opposé du checkbutton en ce sens qu'il ne peut exister que dans un groupe d'options, chacune étant mutuellement
exclusive de toutes les autres. Tous les boutons radio partagent la même variable.
command | Lorsque l'état du widget change, la fonction assosicée est appelée automatiquement. |
image | L'image à utiliser à la place du texte. |
justify | Spécifie comment le texte doit être aligné dans le widget : "left", "center", "right". |
text | Texte à afficher dans le widget. |
value | Chaine de caractères ou valeur entière qui servira à déterminer la valeur prise par le contrôle. |
variable | La variable qui suit l'état du bouton. Pour un checkbutton, par défaut 1 si checked et 0 si unchecked. Pour un radiobutton, stocke la valeur du champ value qui peut être une chaine ou un entier. |
deselect() | Annule l'état de sélection du bouton. |
invoke() | Appelez cette méthode pour obtenir les mêmes actions que si c'était l'utilisateur qui avait cliqué sur le bouton. |
select() | Sélectionne le bouton. |
toggle() | Uniquement pour le checkbutton, toggle() alterne entre l'état coché et décoché. |
import tkinter as tk
def printvar():
print(var1.get())
app = tk.Tk()
# Variable qui va contenir l'état du checkbox
var1 = tk.IntVar()
# L'option command référence la fonction appelée à chaque click sur le bouton
# Cela met à jour la valeur de la variable var1
chk = tk.Checkbutton(app, text='Alors heureux ?', command=printvar, variable=var1)
chk.pack()
app.mainloop()
Le listbox est un widget qui permet d'afficher une liste d'éléments et autorise l'utilisateur à en choisir un ou plusieurs parmi ceux présentés.
selectbackground | Couleur de fond du texte sélectionné. |
selectmode | Nombre d'éléments pouvant être sélectionnés dans la liste : BROWSE, SINGLE, MULTIPLE, EXTENDED. |
xscrollcommand / yscrollcommand | Autorise l'utilisateur à scroller horizontalement / verticalement. |
activate(index) | Sélectionne la liste spécifiée par l'index. |
curselection() | Renvoie un tuple contenant les numéros de ligne du ou des éléments sélectionnés en partant de 0, ou un tuple vide si aucune sélection n'est faite. |
delete(first, last=None) | Supprime les lignes dont les indices sont entre [first, last]. Si le second argument est omis, seule la ligne avec l'indice first est supprimée. |
get(first, last=None) | Retourne un tuple contenant le texte de toutes les lignes qui sont entre les index [first, last]. Si le second argument est omis, la ligne avec l'indice le plus proche de first est renvoyé. |
index(i) | Si possible, positionne la ligne d'index i en haut du widget. |
insert(index, *elements) | Insère une ou plusieurs nouvelles lignes dans le listbox avant la ligne spécifiée par l'index. Utiliser END en tant que premier argument si vous voulez ajouter les nouvelles lignes à la fin du listbox. |
import tkinter as tk
def retrieve():
print(lb.curselection())
app = tk.Tk()
lbl = tk.Label(app, text="liste de courses")
lbl.pack()
lb = tk.Listbox(app)
lb.insert(1, "pain")
lb.insert(2, "viande")
lb.insert(3, "fromage")
lb.insert(4, "oeufs")
lb.pack()
btn = tk.Button(app, text="Récupérer la sélection", command=retrieve)
btn.pack()
app.mainloop()
import tkinter as tk
from tkinter import messagebox
app = tk.Tk()
chk = tkinter.Checkbutton(app, text="alors heureux ?", offvalue=0, onvalue=1)
chk.pack()
radio1 = tk.Radiobutton(app, text="Je suis un homme", value=1)
radio2 = tk.Radiobutton(app, text="Je suis une femme", value=2)
radio3 = tk.Radiobutton(app, text="Je suis les deux", value=2)
radio1.pack()
radio2.pack()
radio3.pack()
scale = tk.Scale(app, from_=10, to=100, tickinterval=25)
scale.pack()
spin = tk.Spinbox(app, from_=1, to=10)
spin.pack()
lb = tk.Listbox(app)
lb.insert(1, "Windows")
lb.insert(2, "Linux")
lb.insert(3, "Mac OS")
lb.pack()
# Boite de message pouvant prendre plusieurs modes
# showerror()
# showinfo()
# showwarning()
# askquestion()
# askokcancel()
# askyesno()
# askretrycancel()
mb = messagebox.showerror("Erreur", "Un problème est survenu")
app.mainloop()