Table des matières

Sujet précédent

Variables de contrôle: Les valeurs sous les widgets

Sujet suivant

Fenêtres de dialogues

Événements: répondre aux actions de l’utilisateur.

Un événement est la survenue de quelquechose dans votre application - par exemple, l’utilisateur appuie sur une touche, clique avec sa souris ou la déplace. Votre application à certainement besoin de réagir à ces actions de l’utilisateur.

Les widgets ont normalement un grand nombre de comportements prédéfinis. Par exemple, un bouton réagira à un clic souris en appelant la fonction associée à son option command. Un autre exemple, si vous déplacez le focus sur un widget de saisie et que vous appuyez sur une lettre, cette lettre sera ajoutée au contenu du widget.

Cependant, tkinter fourni tous les moyens pour ajouter, changer ou supprimer de tels comportements.

Premièrement, quelques définitions:

  • Un événement (event) est la survenue d’une action (clavier, souris) dont votre application a besoin d’être informée.
  • Un gestionnaire d’événement (event handler) est une fonction de votre application qui a vocation a être appelée lorsqu’un certain événement se produira.
  • Nous parlons de liaison lorsque votre application défini un gestionnaire d’événement qui sera effectivement appelé lorsqu’un certain événement se produit sur un widget.

Niveaux de liaisons

Vous pouvez lier un gestionnaire à un événement à l’un de ces niveaux:

  1. Liaison au niveau d’un widget: Vous pouvez lier un événement à un widget particulier. Par exemple, vous pourriez lier la touche PageUp dans un canevas à un gestionnaire qui s’occuperait de le faire défiler d’une page vers le haut. Pour lier un événement à un widget, appelez la méthode bind() sur ce widget (voir Méthodes communes à tous les widgets).

    Par exemple, supposez que vous ayez un canevas référencé par can et que vous souhaitiez dessiner un disque orange sur ce canevas à chaque fois que l’utilisateur appuie sur le bouton 2 de la souris (celui du milieu). Pour définir ce comportement:

    can.bind('<Button-2>', dessineDisqueOrange)
    

    Le premier argument, '<Button-2>', est un «descripteur de séquence» qui indique à tkinter que lorsque le bouton central de la souris est pressé, il faut qu’il appelle le gestionnaire d’événement dessineDisqueOrange fourni comme deuxième argument (Voir Écrire son gestionnaire: la classe Event, ci-dessous, pour une vue d’ensemble sur la manière d’écrire un gestionnaire comme dessineDisqueOrange). Notez qu’il faut omettre les parenthèses du gestionnaire d’événement afin que Python utilise la référence au gestionnaire plutôt que d’essayer de l’appeler sur le champ.

  2. Liaison au niveau de l’application: Vous pouvez définir une liaison d’événement de telle sorte que le gestionnaire d’événement soit appelé indépendament du widget qui a le focus ou qui se trouve sous la souris. Par exemple, vous pourriez souhaiter lier l’événement « appui sur la touche ImprÉcran » à tous les widgets de l’applicatoin de telle sorte que l’écran soit imprimé indépendamment du widget qui a effectivement reçu l’appui sur la touche. Pour lier un événement au niveau de l’application, appeler la méthode bind_all() sur n’importe quel widget (voir Méthodes communes à tous les widgets).

    Voici comment vous pourriez lier l’appui sur la touche, Key, ImprÉcran, Print, à l’effet désiré:

    w.bind_all('<Key-Print>', imprimeEcran)
    

Séquence d’événements

Tkinter dispose d’une méthode générale et puissante pour vous permettre d’indiquer précisément à quels événements vos gestionnaires sont liés.

En général, une séquence d’événements est une chaîne de caractères qui contient un ou plusieurs motifs d’événements. Chaque motif d’événements décrit quelquechose qui peut survenir pendant l’éxécution de votre application. S’il y a plus d’un motif dans une séquence d’événements, le gestionnaire associé sera appelé seulement si tous les motifs de la séquences se produisent en effet.

La forme générale d’un motif d’événement est la suivante:

<[modificateur-]...type[-detail]>
  • Le motif est enfermé entre des chevrons <…>.
  • Le type de l’événement décrit le genre général de celui-ci, comme un appui sur une touche, KeyPress, ou un clic souris, Button. Voir Types d’événements.
  • Vous pouvez indiquer un ou plusieurs modificateurs avant son type pour décrire une combinaison comme un appui sur la touche Maj ou Control pendant qu’une autre touche ou qu’un bouton de la souris est enfoncé. Voir Modificateurs d’événement.
  • Vous pouvez ajouter d’autres détails après le type pour décrire la touche ou le bouton précis qui vous intéresse. Pour les boutons de la souris, 1 indique normalement le bouton de gauche, 2 celui du milieu et 3 celui de droite.
    • Notez qu’il est possible que les boutons de la souris soit inversés si un gaucher a effectué le réglage correspondant de son système.
    • Pour les touches du clavier, il s’agit soit d’un caractère (pour un caractère unique comme pour la touche A ou *) ou le nom d’une touche; voir Noms des touches pour une liste de ces noms.

Voici quelques exemples de motifs d’événements:

  • <Button-1>: L’utilisateur a appuyé sur le premier bouton de la souris (celui de gauche normalement).
  • <KeyRelease-H>: L’utilisateur a relâché la touche H.
  • <Control-Shift-KeyPress-H>: L’utilisateur a appuyé simultanément sur les touches Control, Maj et H.

Vous pouvez aussi utiliser des formes courtes pour préciser un événenemt. Voici quelques exemples:

'<1>' revient au même que '<Button-1>'.

'x' revient au même que '<KeyPress-x>'.

Remarquez que vous pouvez omettre les chevrons '<…>' pour la plupart des caractères, mais que vous ne pouvez pas le faire pour l’espace (dont le nom est '<space>') ou pour le caractère inférieur à < (dont le nom est '<less>').

Types d’événements

L’ensemble complet de tous les types d’événements est très grand, mais beaucoup ne sont pas utilisés fréquemment. Voici la plupart de ceux dont vous aurez besoin:

Type Nom Description
36 Activate Un widget est passé de l’état inactif à l’état actif. Se rapporte au changement de l’option state des widgets comme un bouton qui est inactif (grisé) et devient actif.
4 Button L’utilisateur a appuyé sur l’un des boutons de la souris. La partie détail précise le bouton. Pour la molette de la souris sous Linux, votre gestionnaire distinguera le défilement vers le haut et le défilement vers le bas en examinant l’attribut .num de l’instance d’événement qui lui est fourni; voir Écrire son gestionnaire: la classe Event.
5 ButtonRelease L’utilisateur relâche un bouton de la souris. C’est probablement un meilleur choix dans la plupart des cas d’utiliser ce type d’événement plutôt que Button parce que si l’utilsateur appuie accidentellement sur le bouton, il peut bouger la souris en-dehors du widget pour éviter de lancer l’action.
37 Deactivate Un widget est passé de l’état actif à l’état inactif. Se rapporte au changment de l’option state des widgets comme pour un bouton radio qui change d’état en devenant grisé.
17 Destroy Un widget a été détruit.
7 Enter L’utilisateur a bougé la souris qui est entrée dans la partie visible d’un widget. (Ne pas confondre avec la touche Entrée, qui est un événement de type KeyPress pour une touche dont le nom est 'Return').
2 KeyPress L’utilisateur a appuyé sur une touche du clavier. La partie détail précise optionnellement une touche en particulier. Ce mot clé peut être abrégé par Key.
3 KeyRelease L’utilisateur a relâché une touche du clavier.
8 Leave L’utilisateur a déplacé le pointeur de la souris en dehors d’un widget.
6 Motion L’utilisateur a déplacé la souris à l’intérieur d’un widget.
38 MouseWheel L’utilisateur a tourné la molette de la souris, vers le haut ou vers le bas. Pour l’instant, cela n’est pris en compte que par Windows ou MacOS, mais pas par Linux. Pour ces systèmes, voir la discussion de l’attribut delta d’une instance d’un objet de classe Event dans Écrire son gestionnaire: la classe Event. Pour Linux, se rapporter à la note ci-dessus pour le type Button.

Modificateurs d’événement

Les noms des modificateurs que vous pouvez utiliser dans une séquence d’événements sont, entre autres:

  • Alt : Vrai si l’utilisateur est en train de maintenir enfoncée la touche Alt.
  • Any : Ce modificateur généralise un type d’événement. Par exemple, le motif d’événement '<Any-KeyPress>' correspond à l’appui sur une touche arbitraire.
  • Control : Vrai si l’utilisateur est en train de maintenir enfoncée la touche Ctrl.
  • Double : Indique qu’un événement s’est produit 2 fois dans un cours laps de temps. Par exemple, <Double-Button-1> indique un double clic sur le bouton gauche (normalement) de la souris.
  • Lock : Vrai si l’utilisateur a verrouiller le mode Majuscule.
  • Shift : Vrai si l’utilisateur est en train de maintenir enfoncée la touche Maj.

Noms des touches

La partie detail d’un motif pour un événement KeyPress ou KeyRelease précise la touche que vous souhaitez surveiller. (Voir le modificateur Any ci-dessus si vous souhaitez surveiller toutes les touches).

Le tableau ci-dessous montre plusieurs façons de nommer les touches. Voir Écrire son gestionnaire: la classe Event, ci-dessous, pour plus d’informations sur les objets Event, dont les attributs décrivent les touches de la même manière)

  • La colonne keysym montre le «symbole de touche», une chaîne de caractères pour la touche. Cela correpond à l’attribut keysym des objets Event.
  • La colonne keycode correpond au «code de touche». C’est un identifiant de touche (chaque touche possède un unique keycode) qui permet de savoir quelle touche a été enfoncée. Notez cependant qu’il ne permet pas de savoir si une touche modificatrice (Maj, Ctrl et VerrMaj) a été ou est enfoncée; ainsi, par exemple, a et A ont le même code de touche.
  • La colonne keysym_num montre un code numérique équivalent au symbole de la touche. Il a la particularité d’être différent selon qu’une touche modificatrice a été ou est enfoncée. Par exemple, le chiffre 2 du clavier numérique (dont le symbole de touche est KP_2) et la flèche «sud» du clavier numérique (de symbole KP_Down) ont le même code de touche (88), mais leurs codes numériques keysym_num sont différents (65433 et 65458, respectivement).
  • La colonne Touche montre le texte que vous trouverez habituellement sur la touche de votre clavier, comme Tab par exemple.

Il y a beaucoup de noms de touches pour couvrir de nombreux ensembles de caractères internationaux. Ce tableau montre uniquement l’ensemble «Latin-1» pour un clavier type. Pour connaître l’ensemble des possibilités, reportez-vous à la page correspondante du manuel de Tk.

keysym keycode keysym_num Touche
Alt_L 64 65513 La touche Alt située à gauche.
BackSpace 22 65288 La touche Retour Arrière
Cancel 110 65387 ???
Caps_Lock 66 65509 Verr Maj
Control_L 37 65507 La touche Ctrl de gauche
Control_R 105 65508 La touche Ctrl de droite
Delete 119 65535 Suppr
Down 116 65364
End 115 65367 Fin
Escape 9 65307 Echap
Execute 111 65378 ???
F1 67 65470 La touche fonction F1
F2 68 65471 La touche fonction F2
Fi 66+i 65469+i La touche fonction Fi
F12 96 65481 La touche fonction F12
Home 110 65360 Début
Insert 118 65379 Inser
Left 113 65361
Linefeed 54 106 ??? Linefeed (control-J)
KP_0 90 65456 0 sur le clavier numérique
KP_1 87 65457 1 sur le clavier numérique
KP_2 88 65458 2 sur le clavier numérique
KP_3 89 65459 3 sur le clavier numérique
KP_4 83 65460 4 sur le clavier numérique
KP_5 84 65461 5 sur le clavier numérique
KP_6 85 65462 6 sur le clavier numérique
KP_7 79 65463 7 sur le clavier numérique
KP_8 80 65464 8 sur le clavier numérique
KP_9 81 65465 9 sur le clavier numérique
KP_Add 86 65451 + sur le clavier numérique
KP_Begin 84 65437 La touche centrale (même que 5) sur le clavier numérique
KP_Decimal 91 65454 Symbole de la ponctuation décimale (,) sur le clavier numérique
KP_Delete 91 65439 Suppr sur le clavier numérique
KP_Divide 106 65455 / sur le clavier numérique
KP_Down 88 65433 ↓ sur le clavier numérique
KP_End 87 65436 Fin sur le clavier numérique
KP_Enter 104 65421 Entrée sur le clavier numérique
KP_Home 79 65429 Début sur le clavier numérique
KP_Insert 90 65438 Insert sur le clavier numérique
KP_Left 83 65430 ← sur le clavier numérique
KP_Multiply 63 65450 × sur le clavier numérique
KP_Next 89 65435 PageDown sur le clavier numérique
KP_Prior 81 65434 PageUp sur le clavier numérique
KP_Right 85 65432 → sur le clavier numérique
KP_Subtract 82 65453 - sur le clavier numérique
KP_Up 80 65431 ↑ sur le clavier numérique
Next 117 65366 PageDown
Num_Lock 77 65407 Verr Num
Pause 127 65299 Pause
Print 111 65377 ImprÉcran
Prior 112 65365 PageUp
Return 36 65293 La touche Entrée (control-M). Le nom Enter se réfère à un événement associé à la souris et non au clavier; voir Types d’événements.
Right 114 65363
Scroll_Lock 78 65300 Verrouillage Défilement (ScrollLock)
Shift_L 50 65505 La touche Maj de gauche
Shift_R 62 65506 La touche Maj de droite
space 65 32 La barre espace
Tab 23 65289 La touche de Tabulation, Tab
Up 111 65362

Écrire son gestionnaire: la classe Event

Les sections précédentes vous ont expliquées comment décrire l’événement auquel vous souhaitez réagir et comment le lier à l’application. À présent, intéressons-nous à l’écriture du gestionnaire d’événements qui sera appelé lorsque l’événement aura lieu.

Le gestionnaire d’événements recevra un objet de type Event qui sert à décrire les circonstances de l’événement. Le gestionnaire peut être une fonction ou une méthode. Voici la forme de la déclaration d’une fonction:

def nomGestionnaire(evt):

Et pour une méthode:

class MaClasse:

        # ...

        def nomGestionnaire(self, evt):

Les attributs de l’objet de type Event passé au gestionnaire, par l’intermédiaire de son paramètre evt (parfois noté plus explicitement event), sont décrits ci-dessous. Certains attributs possèdent toujours une valeur, mais d’autres n’en possède une que pour certains types d’événements.

char Si l’événement est produit par l’appui ou le relâchement d’une touche qui produit un caractère ASCII régulier, cet attribut est le caractère sous la forme d’une chaîne. (Pour des touches spéciales comme Suppr, voir l’attribut keysym ci-dessous)
delta Pour un événement du type MouseWheel, cet attribut contient un entier dont le signe est positif pour un déplacement vers le haut, négatif pour un déplacement vers le bas. Sous Windows, cette valeur sera un multiple de 120; par exemple, 120 désigne un défilement vers le haut en une étape et -240 un défilement vers le bas en deux étapes. Sous MacOS, on aurait obtenu les valeurs 1 et -2 dans cet exemple. Pour le support de la molette sous Linux, voir les note sur l’événement de type Button dans Types d’événements.
height Si l’événement est du type Configure, cet attribut porte la nouvelle hauteur du widget en pixels.
keycode Pour un événement de type KeyPress ou KeyRelease, cet attribut contient le code de touche. Cependant, cet entier n’identifie pas quel caractère de la touche a été produit, ainsi «x» ou «X» ne se différencient pas par leur code de touche. Pour des valeurs possibles de cet attribut, voir Noms des touches.
keysym Pour un événement de type KeyPress ou KeyRelease impliquant une touche spéciale, cet attribut porte le nom de touche, par exemple 'Prior' pour la touche PageUp. Voir Noms des touches pour une liste complète des nom de touches.
keysym_num Pour un événement de type KeyPress ou KeyRelease, cet attribut est une version numérique de l’attribut keysym. Pour une touche régulière qui produit un seul caractère, cet attribut prend pour valeur le code ASCII du caractère. Pour des touches spéciales, référez-vous à Noms des touches.
num Si l’événement est associé à un bouton de la souris, cet attribut porte la valeur entière qui indique le numéro du bouton (1, 2 ou 3). Pour le support de la molette sous linux, lier les événements Button-4 et Button-5; lorsque la molette de la souris tourne vers l’avant, cet attribut prend la valeur 4, il prend la valeur 5 dans l’autre sens.
serial Un entier qui est incrémenté à chaque fois que le serveur répond à une requête du client. Vous pouvez utiliser cet attribut pour découvrir la séquence temporelle des événements: ceux qui ont eu lieu plus tôt ont une valeur plus petite.
state Un entier qui décrit l’état de toutes les touches modificatrice. Reportez-vous à la table des masques des modificateurs pour l’interprétation de cette valeur.
time Cet attribut porte un entier qui n’a pas de signification dans l’absolu, mais qui est incrémenté chaque milliseconde. Cela permet à votre application de déterminer, par exemple, le temps écoulé entre deux clic souris.
type Un code numérique qui décrit le type de l’événement. Pour l’interprétation de ce code, reportez-vous à Types d’événements.
widget Porte toujours la référence du widget qui a causé l’événement. Par exemple, si l’événement était un clic souris sur un canevas, cet attribut serait ce canevas.
width Si l’événement était du type Configure, cet attribut est la nouvelle largeur du widget en pixels.
x L’abscisse de la souris en pixels au moment de l’événement. Elle est relative au coin supérieur gauche du widget sur lequel se trouve la souris.
y Similaire à x mais dans la direction verticale.
x_root L’abscisse de la souris au moment où survient l’événement, relativement au coin supérieur gauche de l’écran.
y_root Similaire à x_root mais dans la direction verticale.

Utilisez ces masques pour tester les bits de la valeur de l’attribut state pour savoir quel(s) touche(s) modificatrice(s) et/ou bouton(s) ont été utilisé(s) pendant l’événement.

Masque Modificateur
0x0001 Maj.
0x0002 Verr Maj.
0x0004 Control.
0x0008 Touche Alt de gauche.
0x0010 Verr Num.
0x0080 Touche Alt de droite.
0x0100 Bouton 1 de la souris.
0x0200 Bouton 2 de la souris.
0x0400 Bouton 3 de la souris.

Voici un exemple de gestionnaire d’événements. Plus haut, dans Niveaux de liaisons, vous trouverez un exemple qui vous montre commment lier l’appui sur le bouton central de la souris à un gestionnaire nommé dessineDisqueOrange. Voici ce gestionnaire:

def dessineDisqueOrange(evt):
    '''Dessine un disque orange là où se trouve la souris
    '''
    r = 5   # Son rayon
    can.create_oval(evt.x-r, evt.y-r,
        evt.x+r, evt.y+r, fill='orange')

Lorsque ce gestionnaire est appelé, la position courante de la souris est (evt.x, evt.y). La méthode create_oval() dessine un cercle dont la boîte englobante est un carré centré sur cette position et dont les côtés mesure 2*r.

Astuce pour des arguments en plus de «evt»

Parfois, vous souhaiterez passer d’autres arguments à un gestionnaire (en plus de l’objet Event)

Voici un exemple. Supposez que votre application comporte un tableau de cases à cocher dont les widgets sont mémorisés dans une liste ccList, indexée par le numéro de la case à cocher situé dans range(10).

Supposez en outre que vous souhaitiez n’écrire qu’un gestionnaire ccGest pour l’événement '<Button-1>' sur l’une de ces 10 cases. Votre gestionnaire peut connaître la case sur laquelle a eu lieu le clic en utilisant l’attribut widget de l’objet Event, mais comment faire pour retrouver son index dans la liste ccList ?

Il serait commode d’écrire notre gestionnaire avec un argument supplémentaire pour le numéro de la case à cocher, quelquechose comme:

def ccGest(evt, ccNb):

Mais un gestionnaire d’événement ne reçoit qu’un argument, l’objet de type Event. Il n’est donc pas possible d’utiliser la fonction ci-dessus qui comporte un argument de trop.

Heureusement, il est possible d’exploiter les valeurs par défaut des fonctions pour parvenir à l’objectif. Observer le code suivant:

 ccListe = []
 def creerWidgets():
    #...
    for i in range(10):
        cc = Checkbutton(root, ...)
        ccList.append(cc)
        cc.grid(row=1, column=i)
        def gest(evt, i=i):   1
            return ccGest(evt, i)
        cc.bind('<Button-1>', gest)
    #...
def ccGest(evt, ccNb):
    #...

Ces lignes définissent un gestionnaire, gest() qui attend deux arguments. Le premier est l’objet de type Event habituel et le second a une valeur par défaut qui est exactement celle que nous avons besoin de connaître. Il suffit ensuite de définir le gestionnaire d’événement «réel», ccGest() pour atteindre le but que nous nous étions fixé.

Cette technique peut être étendue pour fournir autant d’arguments que souhaités à un gestionnaire d’événements.