Les signaux GTK+ que nous avons déjà vus concernent les actions de
haut niveau, comme la sélection d'un choix d'un menu. Cependant, il est
utile quelquefois de connaître des possibilités de plus bas niveau, comme le
déplacement de la souris, ou l'appui sur une touche. Il existe aussi des signaux GTK+
correspondants à ces événements de bas niveau. Les gestionnaires de ces signaux possèdent
un paramètre supplémentaire : un objet gtk.gdk.Event
contenant des informations sur l'événement. Par exemple, les gestionnaires des événements
de déplacement recoivent un paramètre gtk.gdk.Event
contenant une
information GdkEventMotion qui contient (en partie) ces attributs :
type # type window # fenêtre time # temps x y ... state # état ...
window
est la fenêtre dans laquelle l'événement est survenu.
x
et y
fournissent les coordonnées de l'événement.
type
sera initialisé avec le type de l'événement,
ici MOTION_NOTIFY
. Ces types (du module gtk.gdk) sont :
NOTHING un code spécial pour indiquer un événement nul. DELETE le gestionnaire de fenêtre a demandé que la fenêtre de plus haut niveau soit cachée ou détruite, d'habitude quand l'utilisateur clique sur une icône spéciale dans la barre de titre. DESTROY la fenêtre a été détruite. EXPOSE tout ou partie de la fenêtre est devenu visible et doit être redessiné. MOTION_NOTIFY le pointeur (d'habitude une souris) a bougé. BUTTON_PRESS on a effectué un clic sur un bouton de la souris. _2BUTTON_PRESS on a effectué un double-clic sur un bouton de la souris (deux clics en un bref temps) sur un bouton de la souris. Note : chaque clic génère aussi un événement BUTTON_PRESS. _3BUTTON_PRESS on a effectué un triple-clic sur un bouton de la souris sur un temps bref. Note : chaque clic génère aussi un événement BUTTON_PRESS. BUTTON_RELEASE le bouton de la souris a été relaché. KEY_PRESS on a appuyé sur une touche. KEY_RELEASE la touche a été relachée. ENTER_NOTIFY le pointeur est entré dans la fenêtre. LEAVE_NOTIFY le pointeur est sorti de la fenêtre. FOCUS_CHANGE le focus de clavier est dans ou a quitté la fenêtre. CONFIGURE la taille, position ou ordre d'empilage a changé. Noter que GTK+ n'utilisa pas ces événements pour les fenêtres enfants GDK_WINDOW_CHILD. MAP la fenêtre a été mappée. UNMAP la fenêtre n'est plus mappée. PROPERTY_NOTIFY une propriété de la fenêtre a été modifiée ou supprimée. SELECTION_CLEAR l'application a perdu la propriété d'une sélection. SELECTION_REQUEST une autre application a réclamé la sélection. SELECTION_NOTIFY une sélection a été reçue. PROXIMITY_IN un dispositif d'entrée a bougé en contact avec une surface sensible (par ex. un écran tactile ou tablette graphique). PROXIMITY_OUT un dispositif d'entrée a bougé en coupant le contact avec une surface sensible DRAG_ENTER la souris est entrée dans la fenêtre pendant une opération glisser. DRAG_LEAVE la souris est sortie de la fenêtre pendant une opération glisser. DRAG_MOTION la souris a bougé dans la fenêtre pendant une opération glisser. DRAG_STATUS l'état de l'opération glisser démarrée par la fenêtre a changé. DROP_START une opération déposer sur la fenêtre a démarrée. DROP_FINISHED une opération déposer initiée par la fenêtre est accomplie. CLIENT_EVENT un message d'une autre application a été reçu. VISIBILITY_NOTIFY l'état de visibilité de la fenêtre a changé. NO_EXPOSE indique que la région source est totalement disponible lorsque des extraits du dessinable sont copiés. Ceci ne présente pas d'intérêt. SCROLL ? WINDOW_STATE ? SETTING ?
Le paramètre state
indique l'état du modificateur
lorsque l'événement
s'est produit (c'est-à-dire quelles
sont les touches de modification et les boutons de souris qui ont été pressés).
Il s'agit d'une opération de bit OR
de certaines des valeurs
(du module gtk.gdk) suivantes :
SHIFT_MASK # masque de majuscules LOCK_MASK # masque de majuscules bloquées CONTROL_MASK # masque de contrôle MOD1_MASK # masque du modificateur 1 MOD2_MASK # masque du modificateur 2 MOD3_MASK # masque du modificateur 3 MOD4_MASK # masque du modificateur 4 MOD5_MASK # masque du modificateur 5 BUTTON1_MASK # masque du bouton 1 BUTTON2_MASK # masque du bouton 2 BUTTON3_MASK # masque du bouton 3 BUTTON4_MASK # masque du bouton 4 BUTTON5_MASK # masque du bouton 5
Comme pour les autres signaux, on appelle la méthode
connect
() pour déterminer ce qui se passe lorsqu'un
événement survient. Mais on doit aussi faire en sorte que GTK+ sache de quels
événements nous voulons être avertis. Pour ce faire, on appelle la méthode :
widget.set_events(events
)
... où events
définit les événements qui nous
intéressent. Il s'agit d'une opération de bit OR
de constantes
qui indiquent différent types d'événements. Pour référence ultérieure,
les types d'événements (du module gtk.gdk) sont :
EXPOSURE_MASK POINTER_MOTION_MASK POINTER_MOTION_HINT_MASK BUTTON_MOTION_MASK BUTTON1_MOTION_MASK BUTTON2_MOTION_MASK BUTTON3_MOTION_MASK BUTTON_PRESS_MASK BUTTON_RELEASE_MASK KEY_PRESS_MASK KEY_RELEASE_MASK ENTER_NOTIFY_MASK LEAVE_NOTIFY_MASK FOCUS_CHANGE_MASK STRUCTURE_MASK PROPERTY_CHANGE_MASK VISIBILITY_NOTIFY_MASK PROXIMITY_IN_MASK PROXIMITY_OUT_MASK SUBSTRUCTURE_MASK
Il y a quelques points subtils qui doivent être observés lorsqu'on
appelle la méthode set_events
(). D'abord, elle doit être
appelée avant que la fenêtre X d'un widget GTK soit créée. En pratique, cela signifie
que l'on doit l'appeler immédiatement après avoir créé le widget. Ensuite, le widget doit
faire partie de ceux réalisés avec une fenêtre X associée. Pour des raisons d'efficacité,
de nombreux types de widgets n'ont pas de fenêtre propre, mais se dessinent dans la fenêtre
de leur parent. Ces widgets sont :
gtk.Alignment gtk.Arrow gtk.Bin gtk.Box gtk.Image gtk.Item gtk.Label gtk.Layout gtk.Pixmap gtk.ScrolledWindow gtk.Separator gtk.Table gtk.AspectFrame gtk.Frame gtk.VBox gtk.HBox gtk.VSeparator gtk.HSeparator
Pour capturer les événements pour ces widgets, on doit utiliser un
widget EventBox
. Voir la Section 10.1, « La boîte à évènement (EventBox) »
pour plus de détails.
Voici les attributs d'événement qui sont définis par PyGTK pour chaque type d'événement :
événement type # type window # fenêtre send_event # événement transmis NOTHING DELETE DESTROY # pas d'attribut supplémentaire EXPOSE area # zone count # nombre MOTION_NOTIFY time # temps x y pressure # pression xtilt # inclinaison en x ytilt # inclinaison en y state # état is_hint # est indice source # source deviceid # identifiant de dispositif x_root # racine x y_root # racine y BUTTON_PRESS _2BUTTON_PRESS _3BUTTON_PRESS BUTTON_RELEASE time # temps x y pressure # pression xtilt # inclinaison en x ytilt # inclinaison en y state # état button # bouton source # source deviceid # identifiant de dispositif x_root # racine x y_root # racine y KEY_PRESS KEY_RELEASE time # temps state # état keyval # valeur de clé string # chaîne de caractères ENTER_NOTIFY LEAVE_NOTIFY subwindow # sous-fenêtre time # temps x y x_root # racine x y_root # racine y mode # mode detail # détail focus # focus state # état FOCUS_CHANGE _in # dans CONFIGURE x y width # largeur height # hauteur MAP UNMAP # pas d'attribut supplémentaire PROPERTY_NOTIFY atom # atome time # temps state # état SELECTION_CLEAR SELECTION_REQUEST SELECTION_NOTIFY selection # sélection target # cible property # propriété requestor # demandeur time # temps PROXIMITY_IN PROXIMITY_OUT time # temps source # source deviceid # identifiant de dispositif DRAG_ENTER DRAG_LEAVE DRAG_MOTION DRAG_STATUS DROP_START DROP_FINISHED context # contexte time # temps x_root # racine x y_root # racine x CLIENT_EVENT message_type # type de message data_format # format de données data # données VISIBILTY_NOTIFY state # état NO_EXPOSE # pas d'attribut supplémentaire
Pour notre programme de dessin, on veut savoir quand le bouton de
la souris est pressé et quand la souris est déplacée, nous indiquons donc
POINTER_MOTION_MASK
et BUTTON_PRESS_MASK
.
On veut aussi savoir quand il est nécessaire de redessiner notre fenêtre,
on indique donc EXPOSURE_MASK
. Bien que nous voulions être
avertis via un événement Configure, d'un redimensionnement de la fenêtre, on n'a
pas besoin de préciser le drapeau STRUCTURE_MASK
correspondant
car il est automatiquement signalé pour chaque fenêtre.
Il peut cependant y avoir un problème en indiquant seulement
POINTER_MOTION_MASK
. Cela fera que le serveur ajoutera un nouvel
événement de déplacement à la file des événements à chaque fois que l'utilisateur
déplace la souris. Imaginons que cela prenne 0,1 seconde pour gérer un événement de
déplacement, mais si le serveur X ajoute un nouvel événement de déplacement dans la
queue toutes les 0,05 secondes, nous serons vite à la traîne de l'utilisateur.
Si l'utilisateur dessine pendant 5 secondes, cela nous prendra 5 secondes de plus
pour le traiter après qu'il ait relâché le bouton de la souris ! Ce que l'on voudrait,
c'est ne récupérer qu'un événement de déplacement pour chaque événement que l'on traite.
Pour cela, il faut préciser POINTER_MOTION_HINT_MASK
.
Quand nous indiquons POINTER_MOTION_HINT_MASK
,
le serveur nous envoit un événement de déplacement la première fois que le
pointeur se déplace après son entrée dans la fenêtre, ou après un événement d'appui
ou de relâchement d'un bouton. Les événements de déplacement suivants seront
supprimés jusqu'à ce que l'on demande explicitement la position du pointeur en
utilisant la méthode gtk.gdk.Window
:
x, y, mask = window.get_pointer()
... où window
est un objet gtk.gdk.Window
,
les paramètres x
et y
sont les coordonnées
du pointeur et mask
est le masque modificateur pour détecter les
touches pressées. (Il existe une méthode get_pointer
() pour
gtk.Widget
qui fournit la même information que la méthode
gtk.gdk.Window get_pointer
() mais ne retourne pas l'indication
de masque des touches
Le programme exemple scribblesimple.py montre l'utilisation de base des événements et des gestionnaires d'événements. La Figure 24.2, « Exemple de Scribble simple » illustre le programme :
Les gestionnaires d'événements sont connectés à la zone de dessin grâce aux ligne suivantes :
92 # Signaux utilisés pour gérer le pixmap hors écran 93 zone_dessin.connect("expose_event", expose_event) 94 zone_dessin.connect("configure_event", configure_event) 95 96 # Signaux d'événements 97 zone_dessin.connect("motion_notify_event", motion_notify_event) 98 zone_dessin.connect("button_press_event", bouton_press_event) 99 100 zone_dessin.set_events(gtk.gdk.EXPOSURE_MASK 101 | gtk.gdk.LEAVE_NOTIFY_MASK 102 | gtk.gdk.BUTTON_PRESS_MASK 103 | gtk.gdk.POINTER_MOTION_MASK 104 | gtk.gdk.POINTER_MOTION_HINT_MASK)
Les gestionnaires d'événement button_press_event
() et
motion_notify_event
()dans
scribblesimple.py
sont ainsi :
57 def bouton_press_event(widget, event): 58 if event.button == 1 and pixmap != None: 59 brosse_dessin(widget, event.x, event.y) 60 return True 61 62 def motion_notify_event(widget, event): 63 if event.is_hint: 64 x, y, etat = event.window.get_pointer() 65 else: 66 x = event.x 67 y = event.y 68 etat = event.state 69 70 if etat & gtk.gdk.BUTTON1_MASK and pixmap != None: 71 brosse_dessin(widget, x, y) 72 73 return True
Les gestionnaires expose_event
() et
configure_event
() seront décrits plus tard.