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

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

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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 language 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 ... Au final, il semble que je n'étais pas dans une si mauvaise voie que cela.

M'inspirant tout d'abord d'un framework JAVA openSource 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 3 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ésent 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 au final 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.

 
Sélectionnez

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'est 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). A 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 :

 
Sélectionnez

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 au final, 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

A 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. A 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 :

 
Sélectionnez

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 multi-hé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. A ce sujet, j'ai des tas de choses à dire mais je pense que je vais m'arrêter là car sinon j'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é 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 indispendable 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 :

 
Sélectionnez

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 ecouteur dans la liste de l'éméteur d'évènement pour l'evenement 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.

Retrouvez cet article et d'autres sur ekameleon.developpez.com ou bien sur mon blog : www.ekameleon.net/blog/

  

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.