Evénements clavier

Dans cette activité, nous allons déplacer un pion sur une surface Canvas en utilisant les touches du clavier pour le diriger.

surface

Mais tout de suite, regardons le programme :


            import tkinter as tk

            # Variables globales
            
            ## Constantes
            LARGEUR = 480
            HAUTEUR = 320
            ## Position initiale du pion
            pos_x = 230
            pos_y = 150
            
            def clavier(event):
                """ Gestion de l'événement Appui sur une touche du clavier """
                global pos_x, pos_y
                touche = event.char
                # déplacement vers le haut
                if touche == 'a':
                    pos_y -= 20
                # déplacement vers le bas
                if touche == 'q':
                    pos_y += 20
                # déplacement vers la droite
                if touche == 'm':
                    pos_x += 20
                # déplacement vers le haut
                if touche == 'l':
                    pos_x -= 20
                # on dessine le pion à sa nouvelle position
                surface_dessin.coords(pion, pos_x-10, pos_y-10, pos_x+10, pos_y+10)
                # Création de la fenêtre principale
            
            # Création de la fenêtre principale (main window)
            mon_app = tk.Tk()
            mon_app.title('Clavier événement')
            
            # Création d'un widget Canvas (zone graphique)
            surface_dessin = tk.Canvas(mon_app, width=LARGEUR, height=HAUTEUR, bg='white')
            surface_dessin.grid(row=0, column=0)
            surface_dessin.focus_set()
            
            # Création du pion sur la surface
            pion = surface_dessin.create_oval(pos_x-10, pos_y-10, pos_x+10, pos_y+10, width=2, fill='red')
            
            # La méthode bind() permet de lier un événement avec une fonction :
            # un appui clavier provoquera l'appel de la fonction clavier()
            surface_dessin.bind('<Key>', clavier)
            
            # Création d'un widget Button (bouton Quitter)
            tk.Button(mon_app, text = 'Quitter', command = mon_app.destroy).grid(row=1, column=0)
            
            mon_app.mainloop()
          

Tester avec repl.it

Explications

Tout d'abord, les coordonnées du pion sont stockées dans les variables globales pos_x et pos_y. La fonction clavier() a pour rôle de les actualiser en fonction de la touche qui a été pressée.

Pour associer l'appel de la fonction Clavier() lorsqu'une touche est pressée, le principe est le même que pour le clic de souris : on appelle la méthode bind() associée à la surface de dessin. L'événement qui nous intéresse ici est désigné par <Key>.

Une petite subtilité ici cependant : pour que la surface capture les événements clavier, il faut qu'elle soit sélectionnée (qu'elle ait le focus comme on dit). On lui donne le focus grâce à la commande


              surface_dessin.focus_set()
            

Nous avons déjà rencontré cette méthode lorsque l'on voulait passer le contrôle à un champ de saisie, le principe est ici le même.

La dernière chose qu'il reste à voir, c'est comment modifier les coordonnées de notre pion lorsque les variables pos_x et pos_y ont été ajustées. Cela se fait par l'appel :


              surface_dessin.coords(pion, pos_x-10, pos_y-10, pos_x+10, pos_y+10)
            

pion est une variable globale créée par la commande create_oval().

A vous de jouer

Dans l'exemple ci-dessus, il n'y a pas de limite au déplacement du pion, même lorsque ce dernier sort du Canvas. Modifier le programme afin que s'il sort d'un coté de la fenêtre, il réapparaisse de l'autre, un peu comme dans le jeu du PacMan.

Une solution


            import tkinter as tk

            # Variables globales
            
            ## Constantes
            LARGEUR = 480
            HAUTEUR = 320
            ## Position initiale du pion
            pos_x = 230
            pos_y = 150
            
            def clavier(event):
                """ Gestion de l'événement Appui sur une touche du clavier """
                global pos_x, pos_y
                touche = event.char
                # déplacement vers le haut
                if touche == 'a':
                    pos_y = (pos_y - 20) % HAUTEUR
                # déplacement vers le bas
                if touche == 'q':
                    pos_y = (pos_y + 20) % HAUTEUR
                # déplacement vers la droite
                if touche == 'm':
                    pos_x = (pos_x + 20) % LARGEUR
                # déplacement vers le haut
                if touche == 'l':
                    pos_x = (pos_x - 20) % LARGEUR
                # on dessine le pion à sa nouvelle position
                surface_dessin.coords(pion, pos_x-10, pos_y-10, pos_x+10, pos_y+10)
                # Création de la fenêtre principale
            
            # Création de la fenêtre principale (main window)
            mon_app = tk.Tk()
            mon_app.title('Clavier événement')
            
            # Création d'un widget Canvas (zone graphique)
            surface_dessin = tk.Canvas(mon_app, width=LARGEUR, height=HAUTEUR, bg='white')
            surface_dessin.grid(row=0, column=0)
            surface_dessin.focus_set()
            
            # Création du pion sur la surface
            pion = surface_dessin.create_oval(pos_x-10, pos_y-10, pos_x+10, pos_y+10, width=2, fill='red')
            
            # La méthode bind() permet de lier un événement avec une fonction :
            # un appui clavier provoquera l'appel de la fonction clavier()
            surface_dessin.bind('<Key>', clavier)
            
            # Création d'un widget Button (bouton Quitter)
            tk.Button(mon_app, text = 'Quitter', command = mon_app.destroy).grid(row=1, column=0)
            
            mon_app.mainloop()