2.10 CONTRÔLE PAR LES ÉVÉNEMENTS

 

 

INTRODUCTION

 

Jusqu’à présent, on a abordé uniquement des programmes ne comportant qu’un seul fil d’événements, les instructions étant exécutées les unes après les autres dans l’ordre du programme avec des boucles et des conditions. Ainsi, le fil d’exécution du programme est complètement déterminé par les paramètres initiaux. Ce modèle ne convient pas bien au pilotage d’un programme avec une souris car on ne peut pas savoir où en est l’exécution du programme lors d’un clic de souris. Pour pouvoir capturer les clics de souris, il faut introduire un nouveau concept de programmation appelé contrôle par les événements ou programmation événementielle. Le principe en est le suivant :

Il faut définir une fonction portant un nom quelconque, par exemple onMouseHit() qui n’est jamais appelée explicitement par le programme. Ensuite, on demander à l’ordinateur d’appeler cette fonction à chaque fois qu’il détecte un clic de souris. En résumé, on demande au programme d’exécuter la fonction onMouseHit() à chaque fois que l’utilisateur clique sur le bouton de la souris.


CONCEPTS DE PROGRAMMATION : Programmation événementielle, événements de la souris.

 

 

ÉVÉNEMENTS DE LA SOURIS

 

Il est très facile d’implémenter ce nouveau concept en Python. Dans notre premier programme dirigé par les événements, la tortue doit dans un premier temps dessiner une figure sympathique. Ensuite, l’utilisateur peut décorer ce dessin initial en cliquant avec la souris sur certaines zones pour les colorier.

Le programme ci-dessous définit la fonction onMouseHit(x, y), qui sera appelée par le système en lui fournissant en guise de paramètres les coordonnées de la souris lors de clic. On peut ensuite utiliser ces coordonnées pour colorier la figure fermée qui entoure le point (x, y)  à l’aide de la fonction fill(x, y).

Il est également capital d’enregistrer notre gestionnaire d’événements de souris onMouseHit() auprès du système. Cela est possible en renseignant le paramètre mouseHit de la  fonction makeTurtle() avec une référence à notre gestionnaire d’événemnts onMouseHit.

Le programme utilise hideTurtle() pour accélérer le dessin.

 
from gturtle import *

def onMouseHit(x, y):
    fill(x, y)      
        
makeTurtle(mouseHit = onMouseHit)
hideTurtle()
addStatusBar(30)
setStatusText("Click to fill a region!")
  
repeat 12:
    repeat 6:
        forward(80)
        right(60)
    left(30)      
Sélectionner le code (Ctrl+C pour copier, Ctrl+V pour coller)

 

 

MEMENTO

 

Du point de vue technique, la programmation événementielle est implémentée en définissant une fonction appelée gestionnaire d’événements (event handler en anglais) qui sera appelée sans que l’on s’en occupe à chaque fois que le système d’exploitation détecte un certain type d’événement. Pour que cela fonctionne, il faut informer le système de notre gestionnaire d’événement en passant le nom de la fonction (sans parenthèse !!!) au paramètre approprié de la fonction makeTurtle(). Pour cela, on utilise la notion très utile en Python de paramètre nommé avec la notation parameter_name = parameter_value.

On peut régler les préférences pour la couleur de remplissage avec la fonction setFillColor().

La fonction addStatusBar(n) permet d’afficher des informations utiles pour l’utilisateur dans une barre d’état en-dessous de la fenêtre de la tortue. Le nombre entier b permet de spécifier la hauteur de ligne du texte affiché dans la barre d’état.

 

 

DESSINER AVEC UN ÉVÉNEMENT DE LA SOURIS

 

Dessinons une étoile possédant des rayons à partir de la position du clic de souris. Pour ce faire, on définit la fonction onMouseHit(x, y), où l’on explique la tortue comme dessiner l’étoile.

Pour que la fonction onMouseHit() soit invoquée par le système lors des clics de souris, on passe au paramètre mouseHit de la fonction makeTurtle() une référence vers notre fonction onMouseHit (remarquer l’absence de parenthèses).

 
from gturtle import *

def onMouseHit(x, y):
    setPos(x, y)
    repeat 6:
        dot(40)
        forward(60)
        back(60)
        right(60)

makeTurtle(mouseHit = onMouseHit)
speed(-1)
Sélectionner le code (Ctrl+C pour copier, Ctrl+V pour coller)

 

 

MEMENTO

 

Ce programme est bogué : si l’utilisateur clique une seconde fois avant que l’étoile précédente ne soit terminée, l’étoile en cours ne va pas être terminée et le programme commence directement le dessin de la seconde étoile. De plus, les instructions non exécutées de l’étoile précédente vont être exécutées dans la deuxième étoile, ce qui mènera à un dessin incorrect de la deuxième étoile.

Ce comportement erroné est apparemment dû au fait qu’à chaque clic de la souris, la fonction onMouseHit() est appelée et exécutée, même si l’exécution précédente n’est pas encore terminée. Pour prévenir ce problème, il faut passer la fonction onMouseHit au paramètre mouseHitX au lieu de mouseHit lors de l’appel de makeTurtle().

 

 

CHASSE À LA SOURIS

 

On aimerait que la tortue suive la souris partout où elle va. On ne peut pas utiliser l’événement du clic de la souris pour cela, car c’est le mouvement de la souris qui nous intéresse. La fonction makeTurtle() reconnaît le paramètre mouseMoved auquel on peut passer la référence vers une fonction qui sera appelée à chaque déplacement de la souris avec les nouvelles coordonnées.

La fonction onMouseMoved(x, y) reçoit les nouvelles coordonnées x et y de la souris.

 
from gturtle import *

def onMouseMoved(x, y):
    setHeading(towards(x, y))
    forward(10)
      
makeTurtle(mouseMoved = onMouseMoved)
speed(-1)
Sélectionner le code (Ctrl+C pour copier, Ctrl+V pour coller)

 

 

MEMENTO

 

En plus de mouseHit et mouseHitX, la fonction makeTurtle() met d’autres paramètres à disposition permettant de détecter des événements de la souris. Ces événements, au lieu de prendre les coordonnées x et y comme paramètres, prennent un seul paramètre event à l’aide duquel on peut déterminer les coordonnées de la souris lors de l’événement ainsi que d’autres informations.

mousePressed Le bouton de la souris est enfoncé
mouseReleased Le bouton de la souris est relâché
mouseClicked Le bouton de la souris est enfoncé et relâché directement (clic)
mouseDragged La souris se déplace pendant que le bouton est enfoncé
mouseMoved La souris a été déplacée
mouseEntered La souris entre dans la fenêtre de la tortue
mouseExited La souris sort de la fenêtre de la tortue

Il est également possible d’enregistrer plusieurs gestionnaires d’événements différents en spécifiant simultanément plusieurs paramètres, par exemple les deux fonctions onMousePressed() et onMouseDragged :

makeTurtle(mousePressed = onMousePressed, mouseDragged = onMouseDragged)

On peut déterminer lequel des boutons a été cliqué grâce aux fonctions isLeftMouseButton() et isRightMouseButton().

Les événements listés ci-dessus comportent une différence importance avec mouseHit : le mouvement de la tortue n’est pas visible pendant l’exécution de la fonction. De ce fait, il faut soit régler la vitesse de la tortue sur ultrarapide avec speed(-1) et cacher la tortue avec hideTurtle() ou alors exécuter le code du mouvement dans la partie principale du programme.


 
from gturtle import *

def onMousePressed(x, y):
    moveTo(x, y)
      
makeTurtle(mousePressed = onMousePressed)
#speed(-1)
#hideTurtle()
Sélectionner le code (Ctrl+C pour copier, Ctrl+V pour coller)

 

 

ÉVÉNEMENTS DU CLAVIER

  À chaque fois qu’une touche du clavier est actionnée, un événement est généré. Pour gérer ce dernier, on enregistre un gestionnaire d’événements en renseignant le paramètre keyPressed. lors de l’appel de la fonction makeTurtle.

Le gestionnaire d’événements reçoit alors en guise de paramètre un nombre entier qui identifie la touche actionnée. Il est possible de découvrir le code généré par chacune des touches du clavier en affichant le nombre entier dans la console avec print et en réalisant quelques expérimentations. Dans le programme suivant, la tortue se déplace de 10 pas en avant tant que le programme tourne. En actionnant les touches directionnelles du clavier, l’utilisateur peut changer son orientation selon les quatre orientations cardinales. Pour éviter que la souris ne quitte la fenêtre, le mode wrap est activé avec l’appel wrap().

 
from gturtle import *

LEFT = 37
RIGHT = 39
UP = 38
DOWN = 40

def onKeyPressed(key):
   if key == LEFT:
      setHeading(-90)
   elif key == RIGHT:
      setHeading(90)
   elif key == UP:
      setHeading(0)
   elif key == DOWN:
      setHeading(180)

makeTurtle(keyPressed = onKeyPressed)
wrap()
while True:
    forward(10)
Ctrl+C pour copier, Ctrl+V pour coller (Ctrl+C pour copier, Ctrl+V pour coller)

 

 

EXERCICES

 

1.

Dessiner l’étoile ci-contre à l’aide d’une boucle et la remplir ensuite avec des clics de souris pour la personnaliser.
 

2.
Réaliser un petit programme de dessin à l’aide de la tortue permettant de dessiner librement avec la souris. Pour cela, abaisser le crayon de la tortue lorsque le bouton de la souris est enfoncé, utiliser l’événement mouseDrag pour tracer les mouvements de la souris et relever le crayon lorsque le bouton est relâché.

 
3.
Compléter le programme précédent en utilisant le bouton gauche de la souris pour dessiner une figure libre et le bouton droit pour colorier des surfaces fermées formées par la trace dessinée.  
4.

Utiliser l'exercice 2 pour créer un programme pour dessiner une figure kaléidoscopique en déplaçant  la souris avec la touche pressée.  La tortue (non visible) trace une ligne simultanément dans les quatre quadrants. Pour dessiner un segment de line, utiliser la fonction suivante:

def line(x1, y1, x2, y2):
    setPos(x1, y1)
    moveTo(x2, y2)

 


5.

Modifier le programme avec  les évènements du clavier de sorte qu'une région fermée dans laquelle se trouve la tortue est colorée en pressant la touche espace (code 32). Utiliser le programme pour dessiner une lettre colorée quelconque.

   

 

 

 

BONUS


 

CURSEUR PERSONNALISÉ

 

On peut sans problème changer la représentation du curseur de souris en spécifiant une image quelconque, ce qui permet de personnaliser le programme. Pour ce faire, il faut appeler la fonction setCursor() et lui passer une des valeurs de la table ci-dessous. Il est même possible de spécifier une image personnelle avec la fonction setCustomCursor(). Un curseur de souris est une image au format PNG ou GIF de 32x32 pixels et possédant un fond transparent. Les curseurs pencil.gif et cutemouse.gif sont déjà présents dans la distribution de TigerJython dans le dossier sprites.

 

Pourquoi ne pas décorer le programme montré précédemment avec l’image cuteturtle  ou votre propre image. Il faut s’assurer que la tortue se déplace toujours vers la souris en utilisant moveTo().

from gturtle import *

def onMouseMoved(x, y):
      moveTo(x, y)
      
makeTurtle(mouseMoved = onMouseMoved)
setCustomCursor("sprites/cutemouse.gif")
speed(-1)
Sélectionner le code (Ctrl+C pour copier, Ctrl+V pour coller)

 

 

MEMENTO

 

L’appel speed(-1) évite d’utiliser les animations de la tortue, ce qui rend les dessins avec moveTo() bien plus rapides.

Paramètres possible pour la fonction setCursor():

Parameter Icon
Cursor.DEFAULT_CURSOR Icône par défaut
Cursor.CROSSHAIR_CURSOR Icône en forme de viseur
Cursor.MOVE_CURSOR Curseur de déplacement (Flèches en forme de croix)
Cursor.TEXT_CURSOR Curseur de saisie de texte (ligne verticale)
Cursor.WAIT_CURSOR Curseur d’attente

Le dossier sprites utilisé pour spécifier à la fonction setCustomCursor() le chemin vers le curseur doit se trouver dans le même dossier que le programme Python.