Gestion des événements dans le framework VEGAS - Partie 2

Marc Alcaraz

Voici un 2e tutoriel introduisant la gestion des événements dans la framework VEGAS en abordant les interfaces EventListener, EventTarget et IeventDispatcher. ♪

- Titre : Gestion des événements dans le framework VEGAS - Partie 2

- Auteur : Marc Alcaraz

- Parution : 7 mai 2007

- Licence : Copyright ® 2006-2007 Marc Alcaraz. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Genèse

- II. Les interfaces EventListener, EventTarget

- III. L'interface IEventDispatcher

- IV. Conclusion

I - Genèse

Il existe maintenant de nombreuses solutions POO pour gérer la propagation des événements dans nos applications ActionScript. Et il est certain que depuis l'apparition des « .onPress » et « .onEnterFrame » dans FLASH MX, j'ai eu le temps d'évoluer au niveau de ma conception d'applications basées sur une communication dite « évènementielle » entre les différents objets qui les composent.

Avec l'arrivée de FLASH MX2004 et de ses composants, c'est la classe EventDispatcher qui est apparue et qui sans être une classe native a laissé un peu en recul l'utilisation de la méthode simple et efficace que propose la classe AsBroadcaster documentée seulement depuis FLASH 8.

Nous nous rendons vite compte que la classe EventDispatcher avec son « mixin » et son code parfois un peu alambiqué se base légèrement sur ce que le W3C propose au niveau des spécifications du DOM Level2 desévénements. Nous retrouvons bien l'utilisation des méthodes addEventListener, removeEventListener et dispatchEvent qui sont en fait exactement les noms préconisés par l'interface EventTarget définie dans les indications pour le langage basé ECMAScript. Maintenant en regardant de plus près les spécifications complètes, il est clair que Macromedia est allé peut-être un peu vite… un peu trop vite ? Je ne pense pas, car il y a des contraintes dans tout travail et parfois il faut, à mon avis, faire avec (mais ceci est une autre histoire :D)

Depuis, le temps passe tranquillement et j'ai pu apprécier d'autres systèmes évènementiels comme celui de Pixlib que j'ai pu utiliser il y a quelques mois et qui est vraiment intéressant, mais c'est surtout avec l'arrivée de l'AS3 et de son nouveau système évènementiel que j'ai vraiment eu le déclic face à un système évènementiel que j'avais déjà commencé à mettre en place peu avant l'arrivée de la première alpha de Flex Builder 2 … Finalement, il semble que je n'étais pas dans une si mauvaise voie que cela.

M'inspirant tout d'abord d'un framework JAVA open source lui-même basé sur le framework COCOA et ensuite de ce que le package flash.events du framework AS3, j'ai pu mettre en place les bases du système évènementiel de VEGAS. Maintenant il serait peut-être temps après cette petite description du pourquoi et du comment de rentrer un peu plus dans des explications plus techniques à ce sujet :)

Je vais commencer par la dualité qu'il existe dans un système évènementiel entre l'objet qui va « émettre » des événements et les objets qui vont les réceptionner et en fonction de cela réagir selon le contexte de celui-ci.

Pour reprendre simplement tout cela par le code et en suivant exactement ce que propose le W3C là-dessus, je peux résumer ce principe en trois interfaces :

- EventTarget : l'interface des diffuseurs d'événements ;

- EventListener : l'interface de ceux qui vont être notifiés des événements ;

- Event : l'interface qui représente l'événement qui est envoyé vers les EventListener par un EventTarget.

J'ai essayé comme je le dis depuis le début de cet article, d'utiliser au « maximum » ce que propose le W3C même si je n'ai pas pu m'empêcher d'ajouter quelques fonctionnalités inspirées à droite et à gauche ou tout simplement par des besoins propres à mon travail quotidien.

Nous nous retrouvons face à 3 types d'objets qui vont avoir chacun leur importance, chacun leur champ d'action et leur façon de fonctionner. J'ai déjà expliqué dans un article sur la classe BasicEvent tout le concept qui tourne autour d'un événement « typé ». Je vais donc me concentrer maintenant sur l'interface EventListener et surtout sur l'interface EventTarget qui permet finalement d'utiliser la classe EventDispatcher (pas celle de Adobe/Macromedia, mais celle de VEGAS :)).

II - Les interfaces EventListener, EventTarget

L'interface EventListener est vraiment la plus simple, il suffit de la regarder quelques instants pour cerner l'essentiel à son sujet.

import vegas.events.Event;

interface vegas.events.EventListener {

/**
* This method is called whenever an event occurs of the type for which the EventListener interface was registered.
*/
function handleEvent(e:Event) ;

}

Tout se résume dans cette simple méthode « handleEvent » qui permet à l'écouteur d'intercepter un événement.

En regardant de plus près dans la classe EventDispatcher de Macromedia, nous retrouvons la possibilité de cibler un objet « écouteur » qui aurait une méthode handleEvent()… Mais cette fonctionnalité est vraiment très mal documentée et surtout avec l'arrivée du typage fort en AS2, il est vraiment dommage que Macromedia n'ait pas cherché à approfondir un tout petit peu plus cette spécification.

Dans VEGAS, un objet sera de type EventListener s'il implémente l'interface EventListener et s'il possède du même coup la méthode handleEvent(e:Event). À partir de ce principe, l'interface EventListener devient un contrat pour le code de vos applications et permet d'identifier correctement tous les objets qui doivent recevoir et réagir à des événements.

Il sera possible bien entendu d'avoir des écouteurs qui vont utiliser une autre méthode que la méthode handleEvent avec une notion de délégation avancée qui permet de créer des EventListener virtuels … mais je vous en reparlerai après avec la classe Delegate, chaque chose en son temps :D

Regardons maintenant de plus près l'interface EventTarget :

import vegas.events.Event;
import vegas.events.EventListener;

interface vegas.events.EventTarget {

function addEventListener( eventName:String, listener:EventListener, useCapture:Boolean, priority:Number, autoRemove:Boolean):Void ;

function dispatchEvent(event, isQueue:Boolean, target, context):Event ;

function removeEventListener(eventName:String, listener, useCapture:Boolean):EventListener ;

}

Vous vous rendez compte si vous avez un peu l'habitude d'utiliser le système EventDispatcher AS2 de Macromedia que les méthodes addEventListener, dispatchEvent et removeEventListener de mon interface ont légèrement plus de paramètres qu'avant. Mais finalement, lorsque l'on regarde ce que propose le tout nouveau framework AS3, c'est pratiquement ce qu'il faut actuellement pour enregistrer des écouteurs et dispatcher correctement des événements.

III - L'interface IEventDispatcher

À noter que l'interface EventTarget est vraiment la base des émetteurs d'événements de VEGAS et qu'en fait, il faut rapidement se tourner vers l'interface beaucoup plus complète IEventDispatcher qui permet d'implémenter complètement des objets de type EventDispatcher. À noter que dans Vegas, comme en AS3, la classe EventDispatcher est instanciable, mais pas que cela…

Voici donc l'interface vraiment plus complète IEventDispatcher :

import vegas.data.Set;
import vegas.events.EventListener;
import vegas.events.EventListenerCollection;
import vegas.events.EventTarget;

interface vegas.events.IEventDispatcher extends EventTarget {

// function addEventListener( eventName:String, listener:EventListener, useCapture:Boolean, priority:Number, autoRemove:Boolean):Void ;

function addGlobalEventListener(listener:EventListener, priority:Number, autoRemove:Boolean):Void ;

// function dispatchEvent(event, isQueue:Boolean, target, context):Event ;

function getEventListeners(eventName:String):EventListenerCollection ;

function getGlobalEventListeners():EventListenerCollection ;

function getRegisteredEventNames():Set ;

function hasEventListener(eventName:String):Boolean ;

// function removeEventListener(eventName:String, listener, useCapture:Boolean):EventListener ;

function removeGlobalEventListener( listener ):EventListener ;

function toString():String ;

}

Il est pratique de pouvoir hériter dans l'interface IEventDispatcher de l'interface EventTarget, j'attends avec impatience le multihéritage des interfaces en AS3 pour approfondir mes besoins au niveau des interfaces dans VEGAS, car je peux difficilement inclure tout ce que je voudrais dans l'interface de mes IEventDispatcher. À ce sujet, j'ai des tas de choses à dire, mais je pense que je vais m'arrêter là, car sinon je n’en finirai jamais avec cet article.

Le plus important maintenant se trouve au niveau de la méthode addEventListener, le premier paramètre de cette méthode et le « eventName » ou si vous préférez, le « type » de l'événement alors que le second paramètre de la méthode sera principalement un objet qui implémente l'interface EventListener. Il n'est plus possible dans VEGAS d'enregistrer un objet qui n'aura pas l'étiquette d'un écouteur de type EventListener !

L'interface IEventDispatcher est bien entendu utilisée par la classe vegas.events.EventDispatcher, mais aussi la classe abstraite AbstractCoreEventDispatcher qui utilise EventDispatcher par composition. Je me suis rendu compte que la classe AbstractCoreEventDispatcher devient très vite indispensable pour pouvoir à tout moment passer le système évènementiel local d'un objet vers un système évènementiel global.

Je vais finir cet article qui résume l'intérêt de bien structurer son code autour d'interfaces solides, avec ici les interfaces Event, EventTarget et EventListener et j'espère pouvoir très vite revenir vers vous pour la suite des aventures du package vegas.events :)

Voici un petit exemple d'utilisation que vous pouvez retrouver dans le répertoire bin/test sur le SVN de OSFlash de VEGAS :

import vegas.events.BasicEvent ;
import vegas.events.Delegate ;
import vegas.events.Event ;
import vegas.events.EventDispatcher ;
import vegas.events.EventListener ;

// ----o Creation de la fonction utilisée par l'écouteur à la réception de l'événement.

var debug = function(ev:Event) {
trace("debug :: " + this + " : " + ev.getType()) ;
}

// ----o Creation de l'écouteur

var listener:EventListener = new Delegate(this, debug) ;

// ----o Creation du diffuseur d'événement

var dispatcher:EventDispatcher = new EventDispatcher() ;

// ----o Ajout d'un écouteur dans la liste de l'émetteur d'événement pour l'événement de type "onTest".

dispatcher.addEventListener("onTest", listener) ;

// ----o Mise en place d'un événement

var e:Event = new BasicEvent("onTest", this, "Hello World") ;

// ----o Lancer la propagation de l'événement.

dispatcher.dispatchEvent(e) ;

IV - Conclusion

Dans un prochain article, je vais essayer de vous parler tout particulièrement des nombreuses possibilités que vous offre la classe EventDispatcher.