Formation I.S.N.

Gestion des événements

Dans une fenêtre programmée à l'aide du module tkinter, les actions de l'utilisateur vont pouvoir modifier ou agir sur les widgets. Ces actions, appelées des événements seront nécessaires au déclenchement de certaines fonctions.

L'instruction :


widget_nom.bind(evenement_nom, fonction)
					

associe l'événement evenement_nom au widget stocké dans la variable widget_nom.
Au déclenchement de l'événement, la fonction fonction est exécutée.

Pour cela, la fonction doit avoir pour seul paramètre event :


def fonction(event):
    """ La fonction « fonction » est associée à un événement."""
				

Quelques événements de la souris

La méthode .bind() accepte comme événement de la souris :

événement Description
'<Motion>' Mouvement de la souris à l'intérieur du widget.
'<Button-1>' Clic (enfoncement) du bouton gauche (1) ou droit (3).
'<ButtonRelease-3>' Relâchement du bouton gauche (1) ou droit (3).
'<Enter>' La souris passe au-dessus du widget.
'<Leave>' La souris «sort» du widget.

Obtenir les coordonnées de la souris

Le programme ci-dessous définit une interface graphique minimaliste avec un Label pour afficher des messages, un Canvas et un Button [Quitter] :


##----- Importation des Modules -----##
from tkinter import *

##----- Définition des Fonctions -----##



##----- Création de la fenêtre -----##
fen = Tk()
fen.title('Mouvements de la souris')

##----- Création des boutons -----##
bouton_quitter = Button(fen, text='Quitter', command=fen.destroy)
bouton_quitter.grid(row=2, column=1, padx=3, pady=3, sticky=S+W+E)

##---- Création des zones de texte -----##
message = Label(fen, text='Ici du texte.')
message.grid(row=0, column=0, columnspan=2, padx=3, pady=3, sticky=W+E)

##----- Création du canevas -----##
dessin=Canvas(fen, bg="white", width=501, height=501)
dessin.grid(row = 1, column = 0, columnspan = 2, padx=5, pady=5)

##----- Programme principal -----##

fen.mainloop()                     # Boucle d'attente des événements
				

Le but de cette application est de voir comment « lier » les mouvements de la souris au Canvas afin de récupérer les coordonnées de la souris et de les afficher à chaque mouvement (en temps réel) dans la zone de texte.

  1. Dans le « programme principal » (ligne 25), appliquer la méthode .bind() au canevas dessin. Associer l'événement de mouvement de la souris à une fonction nommée afficher() :
    
    dessin.bind(...)
    						
  2. Définir la fonction afficher().
    Les coordonnées de la souris sont obtenues avec event.x et event.y. La fonction afficher() doit aussi paramétrer la zone de texte pour afficher en temps réel les coordonnées de la souris dans le canevas.
  3. Que modifier pour prendre en compte l'événement « clic de souris » ?
  • Associer l'événement
  • Une solution
  • Le clic de souris

dessin.bind('<Motion>', afficher)
						

##----- Importation des Modules -----##
from tkinter import *

##----- Définition des Fonctions -----##
def afficher(event):
    """ Entrées : Un événement de la souris
        Sortie : Affiche en temps réel les coordonnées de la souris dans la zone de texte"""
    abscisse = event.x
    ordonnee = event.y
    message.configure(text="Les coordonnées sont X = {} et Y = {}".format(abscisse, ordonnee))

##----- Création de la fenêtre -----##
fen = Tk()
fen.title('Mouvements de la souris')

##----- Création des boutons -----##
bouton_quitter = Button(fen, text='Quitter', command=fen.destroy)
bouton_quitter.grid(row=2, column=1, padx=3, pady=3, sticky=S+W+E)

##---- Création des zones de texte -----##
message = Label(fen, text='Ici du texte.')
message.grid(row=0, column=0, columnspan=2, padx=3, pady=3, sticky=W+E)

##----- Création du canevas -----##
dessin=Canvas(fen, bg="white", width=251, height=251)
dessin.grid(row = 1, column = 0, columnspan = 2, padx=5, pady=5)

##----- Programme principal -----##
dessin.bind('<Motion>', afficher)
fen.mainloop()                     # Boucle d'attente des événements
						

dessin.bind('<Button-1>', afficher)
						

Quelques événements déclenchés par le clavier

La méthode .bind() accepte comme événement du clavier :

événement Description
'<h>' Appui sur la touche h (par exemple).
'<KeyRelease-h>' Relâchement de la touche h (par exemple).

On trouvera la liste des noms des touches du clavier dans le document de référence.

Attention

Un événement du clavier doit être associé à la fenêtre principale car c'est sur elle que porte la boucle des événements.

Un cercle malicieux

Le programme ci-dessous définit une interface graphique minimaliste avec Canvas et un Button [Quitter] :


##----- Importation des Modules -----##
from tkinter import *

##----- Variables globales -----##


##----- Définition des Fonctions -----##


##----- Création de la fenêtre -----##
fen = Tk()
fen.title('Un cercle malicieux')

##----- Création des boutons -----##
bouton_quitter = Button(fen, text='Quitter', command=fen.destroy)
bouton_quitter.grid(row=2, column=1, padx=3, pady=3, sticky=S+W+E)

##----- Création du canevas -----##
dessin=Canvas(fen, bg="white", width=501, height=501)
dessin.grid(row = 1, column = 0, columnspan = 2, padx=5, pady=5)

##----- Objets graphiques -----##



##----- Programme principal -----##

fen.mainloop()                     # Boucle d'attente des événements
				

Le but de cette application est de voir comment « bouger » un cercle (définit dans le canevas) à l'aide des flèches du clavier puis comment modifier aléatoirement la couleur extérieure de ce cercle.

  1. On définit un cercle par son centre et son rayon :
    
    r = 30
    cercle = dessin.create_oval(250-r, 250-r, 250+r, 250+r, width=2)
    						
  2. Dans le programme principal, on applique la méthode .bind() à la fenêtre fen. Pour cela, on associer l'événement « appui sur la flèche haut » ('<Key-Up>') à une fonction nommée haut().
    
    fen.bind(...)
    						
  3. La fonction haut() déplace le cercle vers le haut de la fenêtre. Il faut donc qu'elle puisse déterminer et modifier les coordonnées du cercle. On utilise alors la méthode .coords() appliquée au cercle.
    
    def haut(……………………………):								# Paramètre indispensable ?
    	global cercle									# Variable globale (pas indispensable : c'est un objet...)
    	v = dessin.coords(cercle)						# liste des coordonnées des "coins"
    	v[……] = v[……] …… 10 							# Modification des …………………………
    	v[……] = v[……] …… 10				
    	dessin.coords(cercle, v[0], v[1], v[2], v[3])	# On « retrace » le cercle ailleurs
    						
  4. Lancer le programme et tester la bonne action de la touche [Haut].
  5. Recommencer pour affecter les événements et les fonctions correspondants aux flèches bas ('<Key-Down>'), gauche ('<Key-Left>') et droite ('<Key-Right>').
  6. Définir la liste des couleurs possibles pour le contour du cercle :
    
    coul = ['black', 'red', 'blue', 'green', 'purple', 'yellow', 'orange']
    						
  7. Compléter la définition de la fonction change() qui modifie aléatoirement la couleur du contour du cercle.
    
    def change(……………………………):			# Paramètre indispensable ?
    	global cercle, coul				# Variables globales
    	v = choice(coul)				# choix d'une couleur au hasard
    	dessin.itemconfigure(.....)
    						
  8. Lier cette fonction à l'appui sur la touche espace ('<space>') puis tester le bon comportement du cercle quelle que soit la touche enfoncée.
  9. Pour aller plus loin...
    En faisant des tests plus approfondis, on peut constater que le cercle à la possibilité de sortir du canevas et « disparaître » de la vue de l'utilisateur. Ajouter un test à chacune des fonctions haut(), bas(), gauche() et droite() pour que l'appui sur la touche correspondante ne produise plus aucun effet si le cercle arrive au « bord » du canevas.
  • Test de la touche [Haut]
  • Test des touches de direction
  • Changement de couleur
  • Amélioration

##----- Importation des Modules -----##
from tkinter import *

##----- Variables globales -----##


##----- Définition des Fonctions -----##
def haut(event):									# Paramètre indispensable
	global cercle									# Variable globale (pas indispensable : c'est un objet...)
	v = dessin.coords(cercle)						# liste des coordonnées des "coins"
	v[1] = v[1] - 10 								# Modification des ordonnées
	v[3] = v[3] - 10
	dessin.coords(cercle, v[0], v[1], v[2], v[3])	# On « retrace » le cercle ailleurs

##----- Création de la fenêtre -----##
fen = Tk()
fen.title('Un cercle malicieux')

##----- Création des boutons -----##
bouton_quitter = Button(fen, text='Quitter', command=fen.destroy)
bouton_quitter.grid(row=2, column=1, padx=3, pady=3, sticky=S+W+E)

##----- Création du canevas -----##
dessin=Canvas(fen, bg="white", width=501, height=501)
dessin.grid(row = 1, column = 0, columnspan = 2, padx=5, pady=5)

##----- Objets graphiques -----##
r = 30
cercle = dessin.create_oval(250-r, 250-r, 250+r, 250+r, width=2)

##----- Programme principal -----##
fen.bind('<Key-Up>', haut)
fen.mainloop()                     # Boucle d'attente des événements
						

##----- Importation des Modules -----##
from tkinter import *

##----- Variables globales -----##


##----- Définition des Fonctions -----##
def haut(event):									# Paramètre indispensable
	global cercle									# Variable globale (pas indispensable : c'est un objet...)
	v = dessin.coords(cercle)						# liste des coordonnées des "coins"
	v[1] = v[1] - 10 								# Modification des ordonnées
	v[3] = v[3] - 10
	dessin.coords(cercle, v[0], v[1], v[2], v[3])	# On « retrace » le cercle ailleurs

def bas(event):
	global cercle
	v = dessin.coords(cercle)
	v[1] = v[1] + 10 								# Modification des ordonnées
	v[3] = v[3] + 10
	dessin.coords(cercle, v[0], v[1], v[2], v[3])

def gauche(event):
	global cercle
	v = dessin.coords(cercle)
	v[0] = v[0] - 10 								# Modification des abscisses
	v[2] = v[2] - 10
	dessin.coords(cercle, v[0], v[1], v[2], v[3])

def droite(event):
	global cercle
	v = dessin.coords(cercle)
	v[0] = v[0] + 10 								# Modification des abscisses
	v[2] = v[2] + 10
	dessin.coords(cercle, v[0], v[1], v[2], v[3])

##----- Création de la fenêtre -----##
fen = Tk()
fen.title('Un cercle malicieux')

##----- Création des boutons -----##
bouton_quitter = Button(fen, text='Quitter', command=fen.destroy)
bouton_quitter.grid(row=2, column=1, padx=3, pady=3, sticky=S+W+E)

##----- Création du canevas -----##
dessin=Canvas(fen, bg="white", width=501, height=501)
dessin.grid(row = 1, column = 0, columnspan = 2, padx=5, pady=5)

##----- Objets graphiques -----##
r = 30
cercle = dessin.create_oval(250-r, 250-r, 250+r, 250+r, width=2)

##----- Programme principal -----##
fen.bind('<Key-Up>', haut)
fen.bind('<Key-Down>', bas)
fen.bind('<Key-Left>', gauche)
fen.bind('<Key-Right>', droite)
fen.mainloop()                     # Boucle d'attente des événements
						

##----- Importation des Modules -----##
from tkinter import *
from random import *

##----- Variables globales -----##
coul = ['black', 'red', 'blue', 'green', 'purple', 'yellow', 'orange']

##----- Définition des Fonctions -----##
def haut(event):									# Paramètre indispensable
	global cercle									# Variable globale (pas indispensable : c'est un objet...)
	v = dessin.coords(cercle)						# liste des coordonnées des "coins"
	v[1] = v[1] - 10 								# Modification des ordonnées
	v[3] = v[3] - 10
	dessin.coords(cercle, v[0], v[1], v[2], v[3])	# On « retrace » le cercle ailleurs

def bas(event):
	global cercle
	v = dessin.coords(cercle)
	v[1] = v[1] + 10 								# Modification des ordonnées
	v[3] = v[3] + 10
	dessin.coords(cercle, v[0], v[1], v[2], v[3])

def gauche(event):
	global cercle
	v = dessin.coords(cercle)
	v[0] = v[0] - 10 								# Modification des abscisses
	v[2] = v[2] - 10
	dessin.coords(cercle, v[0], v[1], v[2], v[3])

def droite(event):
	global cercle
	v = dessin.coords(cercle)
	v[0] = v[0] + 10 								# Modification des abscisses
	v[2] = v[2] + 10
	dessin.coords(cercle, v[0], v[1], v[2], v[3])

def change(event):
	global cercle, coul				# Variables globales
	v = choice(coul)				# choix d'une couleur au hasard
	dessin.itemconfigure(cercle, outline=v)

##----- Création de la fenêtre -----##
fen = Tk()
fen.title('Un cercle malicieux')

##----- Création des boutons -----##
bouton_quitter = Button(fen, text='Quitter', command=fen.destroy)
bouton_quitter.grid(row=2, column=1, padx=3, pady=3, sticky=S+W+E)

##----- Création du canevas -----##
dessin=Canvas(fen, bg="white", width=501, height=501)
dessin.grid(row = 1, column = 0, columnspan = 2, padx=5, pady=5)

##----- Objets graphiques -----##
r = 30
cercle = dessin.create_oval(250-r, 250-r, 250+r, 250+r, width=2)

##----- Programme principal -----##
fen.bind('<Key-Up>', haut)
fen.bind('<Key-Down>', bas)
fen.bind('<Key-Left>', gauche)
fen.bind('<Key-Right>', droite)
fen.bind('<space>', change)
fen.mainloop()                     # Boucle d'attente des événements
						

##----- Importation des Modules -----##
from tkinter import *
from random import *

##----- Variables globales -----##
coul = ['black', 'red', 'blue', 'green', 'purple', 'yellow', 'orange']
r = 30												# Rayon du cercle
dim = 500											# Dimensions du canevas carré

##----- Définition des Fonctions -----##
def haut(event):
	global cercle, r
	v = dessin.coords(cercle)
	if v[1] > 10:
		v[1] = v[1] - 10 							# Modification des ordonnées
		v[3] = v[3] - 10
		dessin.coords(cercle, v[0], v[1], v[2], v[3])

def bas(event):
	global cercle, r
	v = dessin.coords(cercle)
	if v[3] < dim-10:
		v[1] = v[1] + 10 							# Modification des ordonnées
		v[3] = v[3] + 10
		dessin.coords(cercle, v[0], v[1], v[2], v[3])

def gauche(event):
	global cercle, r
	v = dessin.coords(cercle)
	if v[0] > 10:
		v[0] = v[0] - 10 							# Modification des abscisses
		v[2] = v[2] - 10
		dessin.coords(cercle, v[0], v[1], v[2], v[3])

def droite(event):
	global cercle, r
	v = dessin.coords(cercle)
	if v[2] < dim-10:
		v[0] = v[0] + 10 							# Modification des abscisses
		v[2] = v[2] + 10
		dessin.coords(cercle, v[0], v[1], v[2], v[3])

def change(event):
	global cercle, coul				# Variables globales
	v = choice(coul)				# choix d'une couleur au hasard
	dessin.itemconfigure(cercle, outline=v)

##----- Création de la fenêtre -----##
fen = Tk()
fen.title('Un cercle malicieux')

##----- Création des boutons -----##
bouton_quitter = Button(fen, text='Quitter', command=fen.destroy)
bouton_quitter.grid(row=2, column=1, padx=3, pady=3, sticky=S+W+E)

##----- Création du canevas -----##
dessin=Canvas(fen, bg="white", width=dim+1, height=dim+1)
dessin.grid(row = 1, column = 0, columnspan = 2, padx=5, pady=5)

##----- Objets graphiques -----##
cercle = dessin.create_oval(dim/2-r, dim/2-r, dim/2+r, dim/2+r, width=2)

##----- Programme principal -----##
fen.bind('<Key-Up>', haut)
fen.bind('<Key-Down>', bas)
fen.bind('<Key-Left>', gauche)
fen.bind('<Key-Right>', droite)
fen.bind('<space>', change)
fen.mainloop()                     # Boucle d'attente des événements