Les interfaces graphiques servent à rendre les programmes plus conviviaux. Elles sont pratiques
à utiliser mais elles demandent un peu de temps pour les concevoir.
Un programme fonctionne de manière différente. Il n’exécute plus successivement les
instructions mais attend un événement - pression d’une
touche du clavier, clic de souris - pour exécuter une fonction.
C’est comme si le programme avait une multitude de points d’entrée.
Il existe plusieurs modules permettant d’exploiter les interfaces graphiques. Le plus simple est le module tkinter présent lors de l’installation du langage Python. Ce module est simple mais limité. Le module wxPython est plus complet mais un peu plus compliqué dans son utilisation. Toutefois, le fonctionnement des interfaces graphiques sous un module ou un autre est identique. C’est pourquoi ce chapitre n’en présentera qu’un seul, le module tkinter. Pour d’autres modules, les noms de classes changent mais la logique reste la même : il s’agit d’associer des événements à des parties du programme Python.
Les interfaces graphiques évoluent sans doute plus vite que les autres modules, des composantes de plus en plus complexes apparaissent régulièrement. Un module comme wxPython change de version plusieurs fois par an. Il est possible de trouver sur Internet des liens qui donnent des exemples de programme. Une excellente source de documentation sont les forums de discussion qui sont un lieu où des programmeurs échangent questions et réponses. Un message d’erreur entré sur un moteur de recherche Internet permet souvent de tomber sur des échanges de ce type, sur des problèmes résolus par d’autres.
Introduction
Un programme muni d’une interface graphique fonctionne différemment d’un programme classique. Un programme classique est une succession presque linéaire d’instructions.
Il y a un début ou point d’entrée du programme et aucun événement extérieur ne vient troubler son déroulement Avec une interface graphique, le point d’entrée du programme est masqué : il est pris en compte automatiquement. Du point de vue du programmeur, le programme a plusieurs points d’entrée : une simple fenêtre avec deux boutons propose deux façons de commencer et il faut prévoir une action associée à chaque bouton. La conception d’une interface graphique se déroule généralement selon deux étapes. La première consiste à dessiner l’interface, c’est-à-dire choisir une position pour les objets de la fenêtre (bouton, zone de saisie, liste déroulante, ...). La seconde étape définit le fonctionnement de la fenêtre, c’est-à-dire associe à chaque objet des fonctions qui seront exécutées si un tel événement se réalise (pression d’un bouton, pression d’une touche, ...).
Pour le moment, nous allons supposer que ces deux étapes sont scindées même si elles sont parfois entremêlées lorsqu’un événement implique la modification de l’apparence de la fenêtre. Nous allons décrire des objets que propose le module tkinter. Ensuite on présente la manière de les disposer dans une fenêtre et on décrit les événements et le moyen de les relier à des fonctions du programme. Enfin nous allons voir comment gérer des images c’est-à-dire comment dessiner sur la fenêtre, placer des images et les déplacer.
Nous allons voir dans ce chapitre comment dessiner sur la fenêtre, placer des images et les déplacer.
Le widget Canvas
Le module tkinter dispose d’un widget nommé Canvas destiné à dessiner sur la fenêtre. Si on veut créer un canvas nommé C, l’appel se fait comme pour tous les widgets de la manière suivante :
C = Canvas(emplacement, options)
Où emplacement est le nom de la fenêtre sur laquelle il est déposé et options indique les différentes propriétés du Canvas comme :
Options | Effet |
bg | Précise la couleur du fond du Canvas. |
width height | Précisent respectivement la largeur et la hauteur du Canvas (en pixels). |
Attention
Il faut penser comme tous les widgets, une fois le Canvas créé, il faut encore le placer sur la fenêtre avec la méthode place, grid ou pack présentée au paragraphe précédent.
Dessiner sur le canvas
Sur un Canvas ici noté C, on peut dessiner différents types d’objets que l’on appelle item. Nous n’allons pas aborder qu’une infime partie des possibilités offertes par Canvas.
Une ligne
L’instruction : ligne = C.create_line(x1,y1,x2,y2,options),
dessine un segment reliant le point de coordonnées (x1 ; y1) (inclus) au point de coordonnées (x2 ; y2) (exclu).
On peut préciser des options :
Options | Effet |
width | Epaisseur de la ligne en pixels. |
fill | Couleur de la ligne. |
Exemple 9
from tkinter import *
fen = Tk() # crée la fenêtre nommée fen
fen.geometry("200x100")
fen.title("Segment")
C = Canvas(fen, width = 200, height = 100, bg = 'black')
C.place(x=0,y=0)
ligne = C.create_line(0,0,180,80,width = 2,fill = 'red')
fen.mainloop()
On obtient :
Rectangle
L’instruction : rectangle = C.create_rectangle(x1,y1,x2,y2,options)
dessine un rectangle dont deux sommets opposés (le premier en haut à gauche et le second à droite en bas) ont pour coordonnées (x1 ; y1) et (x2 ; y2).
On peut également préciser des options :
Options | Effet |
width | Epaisseur du trait en pixels. |
outline | Couleur du trait. |
fill | Couleur de l’intérieur du rectangle |
Exemple 10
from tkinter import *
fen = Tk() # crée la fenêtre nommée fen
fen.geometry("200x100")
fen.title("Segment")
C = Canvas(fen, width = 200, height = 100, bg = 'black')
C.place(x=0,y=0)
rectanle = C.create_rectangle(70,10,110,80,width = 3,
outline = 'red', fill = 'yellow')
fen.mainloop()
On obtient :
Une ellipse ou un cercle
dessine une ellipse inscrite dans un rectangle (imaginaire) dont deux sommets opposés (le premier en haut à gauche et le second à droite en bas) ont pour coordonnées (x1 ; y1) et (x2 ; y2).
create_oval possède les mêmes options que create_rectangle.
Remarque
Pour dessiner un cercle les coordonnées (x1 ; y1) et (x2 ; y2) doivent vérifier la condition : x2 – x1 = y2 – y1.
Exemple 11
from tkinter import *
fen = Tk() # crée la fenêtre nommée fen
fen.geometry("200x100")
fen.title("Disque")
C = Canvas(fen, width = 200, height = 100, bg = 'white')
C.place(x=0,y=0)
cercle = C.create_oval(70,10,150,90,width = 3,outline = 'red', fill = 'blue')
fen.mainloop()
On obtient :
Afficher un texte sur un Canvas
L’instruction : texte = C.create_text(x, y, options)
permet d'afficher le texte à partir du point
de coordonnées (x ; y) du Canvas C créé.
On peut également préciser des options :
Options | Effet |
anchor | Précise la position d’attache du texte par rapport au point de coordonnées (x ; y). Par défaut, le texte est centré autour du point indiqué (‘center’). Il peut aussi prendre les valeurs ‘n’, ‘e’, ‘s’, ‘w’, ‘nw’, ‘ne’, ‘sw’ ou ‘se’ |
fill | Couleur du texte. |
font | Police de caractères utilisée (comme pour le widget Label) |
text | Une chaîne de caractères contenant le texte à afficher. |
Exemple 12
from tkinter import *
import random
fenetre=Tk()
fenetre.title("Bonne année")
fenetre.geometry("500x300")
Fond=Canvas(fenetre,width=500,height=300,bg="black")
Fond.place(x=0,y=0)
#Lignes
Fond.create_line(0,50,250,10,fill='green')
Fond.create_line(250,10,500,50,fill='green')
Fond.create_line(250,20,500,80,fill='green')
Fond.create_line(0,80,250,20,fill='green')
#Boules
Fond.create_oval(400,200,450,250,fill= 'cyan')
Fond.create_oval(100,80,160,140,fill= 'purple')
Fond.create_oval(200,100,240,140,fill= 'white')
Fond.create_oval(220,220,250,250,fill= 'yellow')
Fond.create_text(250,150,text="Bonne année 2015 !",font=("Arial",30), fill='red')
fenetre.mainloop()
On obtient :
Placer des images
Il existe différents formats. Le module tkinter travaille très bien avec les images au format GIF (non animées). Ce sont des images en 256 couleurs.
Placer une image n’est pas plus complexe qu’afficher un texte, cela se passe en deux étapes :
- Etape 1 : On charge l’image dans une variable globale (ici fichierimg) à l’aide de la commande
Fichierimg = PhotoImage(file ="image.gif")
- Etape 2 : place l’image au point de coordonnées x, y sur le Canvas C avec la méthode
Img = C.create_image(x, y, options)
Le paramètre options permet de renseigner les propriétés. Par exemple
Options | Effet |
image | Indique l’image à afficher (fichierimg dans l’exemple que nous avons présenté). |
anchor | Comme pour objet text, indique la position du point de référence (x ; y) par rapport au reste de l’image. Par défaut, le texte est centré autour du point indiqué). Il peut prendre les valeurs ‘n’, ‘e’, ‘s’, ‘w’, ‘nw’, ‘ne’, ‘sw’, ‘se’ ou ‘center’ (Par défaut). |
Remarque
Comme pour les fichiers, vous pouvez indiquer un chemin relatif pour l’emplacement de l’image si celle-ci ne se trouve pas au même endroit que votre programme.
Exemple 13
L'objectif de cet exemple est de créer un fichier texte fichierISN.txt et placer des images à la place des caractères.
from tkinter import *
#Ouverture d'un fichier nommé fichierISN.txt pour y écrire du texte
fichier = open("fichierISN.txt","w")
liste = [[' ' for j in range(20)] for i in range(10)]
liste[0][0]='C'
for i in range(1,9):
liste[i][i+10] = 'N'
for i in range(2,6):
liste[i][i] = 'S'
for i in range(10):
for j in range(20):
if j ==10 or j == 19 :
liste[i][j] = 'N'
elif i>1 and j == 0 :
liste[i][j] = 'I'
elif (i == 0 or i == 9) and (j==3 or j == 5 or j == 7) :
liste[i][j] = 'S'
elif (i == 1 or i == 8) and (j == 2 or j == 8) :
liste[i][j] = 'S'
elif (i == 6 or i == 7) and j == i+1 :
liste[i][j] = 'S'
for i in range(10):
chaine = ''
for j in range(20):
chaine = chaine+''+str(liste[i][j])
print(chaine,file=fichier)
fichier.close()
#Transformation des caractères du fichier texte fichierISN en images
fenetre=Tk()
fenetre.title("Plateforme !")
fenetre.geometry("880x500")
Fond=Canvas(fenetre,width=880,height=500,bg="#BBBBF9")
Fond.place(x=0,y=0)
F_Acier=PhotoImage(file="acier.gif")
F_Brique=PhotoImage(file="brique.gif")
F_coc=PhotoImage(file="coc.gif")
x, y = 10, 30
fichier = open("fichierISN.txt", 'r')
for ligne in fichier :
for i in range(len(ligne)) :
case = ligne[i]
if case == 'S' :
Fond.create_image(x,y,image=F_Acier,anchor="nw")
if case == 'I':
Fond.create_image(x,y,image=F_Brique,anchor="nw")
if case == 'N':
Fond.create_image(x,y,image=F_Brique,anchor="nw")
if case == 'C':
Fond.create_image(x,y,image=F_coc,anchor="nw")
x = x + 40
x = 10
y = y + 40
fichier.close()
fenetre.mainloop()
On obtient :
Modifier les items en cours de programme
A présent que nous savons placer des images et autres items sur la fenêtre, il est important de pouvoir les déplacer ou les modifier au fur et à mesure du jeu.
Changer les propriétés
Diverses méthodes sur le widget Canvas permettent de modifier les propriétés des items placés :
Méthodes | Effet |
C.delete(item) | Efface l’item 'item' du Canvas C. |
C.delete(ALL) | Efface tout ce qui se trouve sur le Canvas C. |
C.coords(item,x0, y0) C.coords(item,x1, y1, x2, y2)) | Modifie les coordonnées de l’item 'item' (2 ou 4 selon l’objet). |
C.itemconfig(item, options) | Permet de modifier une ou plusieurs options de l’item 'item'. |
C.itemcget(item, prop) | Renvoie la valeur de la propriété prop de l’item 'item'. |
Si on souhaite modifier plusieurs options d’un coup, on sépare les propriétés par une virgule, par exemple :
....
C.itemconfig(T , text = 'Gagné ', fill = 'red')
...
transforme le contenu du texte T placé sur le Canvas C en "Gagné" écrit en rouge.
Exemple 14
from tkinter import *
fenetre=Tk()
fenetre.title("Vous avez gagné !")
Fond=Canvas(fenetre,bg="white", width=200, height = 200)
Fond.grid()
T = Fond.create_text(100,100,text="Gagné")
Fond.itemconfig(T,text = 'Perdu')
fenetre.mainloop()
Déplacement d'une image
En s'inspirant de l'exercice Sur le télécran, on peut créer des boutons qui permettent de commander le déplacement d'une coccinelle dans les quatre directions.
Selon la direction du déplacement, l’image de la coccinelle sera modifiée :
Exemple 15
fenetre=Tk()
fenetre.title("FaireBougerImage")
F_cocH = PhotoImage(file="cocH.gif")
F_cocB = PhotoImage(file="cocB.gif")
F_cocG = PhotoImage(file="cocG.gif")
F_cocD = PhotoImage(file="cocD.gif")
def haut():
global y, img
Fond.create_image(x, y-10, image = F_cocH)
y = max (0,y-10)
def bas():
global y
Fond.create_image(x, y+10, image = F_cocB)
y = min (400,y+10)
def gauche():
global x
Fond.create_image(x-10, y, image = F_cocG)
x = max (0,x-10)
def droite():
global x
Fond.create_image(x+10, y, image = F_cocD)
x = min (400,x+10)
Fond=Canvas(fenetre,width=400,height=400,bg="white")
Fond.grid(column=0,row=0, rowspan = 8)
Button(fenetre,text="HAUT",command=haut).grid(column=1,row=0)
Button(fenetre,text="BAS",command=bas).grid(column=1,row=1)
Button(fenetre,text="GAUCHE",command=gauche).grid(column=1,row=2)
Button(fenetre,text="DROITE",command=droite).grid(column=1,row=3)
x, y = 200, 200
img = Fond.create_image(200,200,image=F_cocH,anchor='nw')
fenetre.mainloop()
Remarque
Vous avez remarqué que ce programme a un défaut puisque le déplacement des images laisse des traces.
Pour corriger ce défaut on pourrait utiliser les méthodes
C.itemconfig(item, options) et C.coords(item,x, y)
Profondeurs des objets
Vous l’aurez sûrement remarqué, les objets images se superposent dans l’ordre dans lequel ils sont créés, c’est-à-dire que si vous créez d’abord un personnage, puis le fond, vous ne verrez pas votre héros puisqu’il sera derrière le décor.
On peut en cours de programme modifier cet ordre grâce à deux méthodes détaillées ici :
Méthodes | Effet |
C.tag_raise(obj) | Place l’objet obj en premier plan du Canvas C. |
C.tag_lower(obj) | Place l’objet obj en arrière plan du Canvas C. |