Comunidad de diseño web y desarrollo en internet

Comunicación entre clases Actionscript 3 con EventDispatcher

A raíz de una pregunta en un tip anterior explicaré cómo detectar eventos personalizados entre clases de Actionscript 3. Para poder, por ejemplo, que una clase pueda detectar cuando otra clase a ejecutado una acción en concreto o ha completado una carga de datos externa.

La interfaz IEventDispatcher define métodos para añadir o quitar detectores de eventos. Son muchas las clases que implementan esta interfaz y por lo tanto permiten lanzar y escuchar eventos, cómo lo es la clase DisplayObject con lo que en cualquier clip podremos añadirle un detector de "escuche" (por ejemplo) el evento que lanza automáticamente la clase MouseEvent cada vez que hacemos click sobre él:

Código :

clip.addEventListener(MouseEvent.CLICK, detectaEvento);

function detectaEvento(e:MouseEvent):void
{
   trace("Detecto el mouse click");
}


Ahora bien, conel método dispatchEvent() podemos lanzar nuestros propios eventos desde nuestras clases. ünicamente crearemos un evento con el nombre que queramos.

Código :

dispatchEvent(new Event("onClick"));


y para detectar:

Código :

addEventListener("onClick",detectaEvento);


Para hacerlo de una manera un poco más elegante podríamos crear una constante estática que guarde el nombre del evento. De esta manera una clase de ejemplo sería asi:

Código :

package 
{
   import flash.display.Sprite;
   import flash.events.EventDispatcher;
   import flash.events.Event;
   import flash.events.MouseEvent;
   //
   public class ClaseA extends Sprite
   {
      public static  const CLICK:String = "onClick";
      //
      public function ClaseA()
      {
         var clip:Sprite = new Sprite();
         clip.graphics.beginFill(0x000000);
         clip.graphics.drawRect(0, 0, 50, 50);
         clip.graphics.endFill();
         addChild(clip);
         addEventListener(MouseEvent.CLICK, lanzaEvento);
         addEventListener(ClaseA.CLICK, detectaEvento);
      }
      private function lanzaEvento(e:MouseEvent):void
      {
         trace("Detecto el mouse click");
         dispatchEvent(new Event(ClaseA.CLICK));
      }
      private function detectaEvento(e:Event):void
      {
         trace("Detecto el ClaseA click");
      }
   }
}


Esta clase crear un gráfico que detecta el click del mouse, y a su vez lanza y detecta su propio evento.

Lo interesante es poder detectar estos eventos desde fuera de la clase. Por ejemplo, crearemos otra clase que detecte este evento lanzado por la ClaseA:

Código :

package 
{
   import flash.display.Sprite;
   import flash.events.Event;
   //
   public class ClaseB extends Sprite
   {
      private var claseA:ClaseA;
      //
      public function ClaseB()
      {
         claseA = new ClaseA();
         claseA.addEventListener(ClaseA.CLICK,detectaEvento);
         addChild(claseA);
      }
      private function detectaEvento(e:Event):void
      {
         trace("Detecto el ClaseA click");
      }
   }
}


Cómo vemos, para poder detectar el evento de una clase hemos de asignarle el addEventListener a su instancia. Es decir, este listener en la claseB no funcionaría:

Código :

claseA = new ClaseA();
addChild(claseA);
addEventListener(ClaseA.CLICK,detectaEvento);


Entonces ¿cómo detectaremos eventos de clases que no están incluidas en las clases detectoras?
Tendremos que hechar mano de una clase intermedia (dispatcher) que sea la que realmente lance el evento:

Código :

package 
{
   import flash.events.EventDispatcher;
   //
   public class ClaseDispatcher extends EventDispatcher
   {
      private static var _instancia:ClaseDispatcher;
      public static  const CLASEA_CLICK:String = "onClick_en_claseA";
      //
      public function ClaseDispatcher(s:Singleton)
      {
      }
      public static function getInstancia():ClaseDispatcher
      {
         if (_instancia == null) {
            ClaseDispatcher._instancia = new ClaseDispatcher(new Singleton);
         }
         return _instancia;
      }
   }
}
class Singleton
{
}

Esta clase está escrita siguiendo el patrón Singleton para que solo se pueda crear una única instancia y esta sea accesible dese cualquier clase (ya escribiré un tip haciendo una explicación más extensa sobre este patrón ;)) .

De manera que incluyendo esta clase dispatcher dentro de las clases que queramos mantener comunicadas:

Código :

package 
{
   import flash.display.Sprite;
   import flash.events.EventDispatcher;
   import flash.events.Event;
   import flash.events.MouseEvent;
   //
   public class ClaseA extends Sprite
   {
      private var dispatcher:ClaseDispatcher;
      //
      public function ClaseA()
      {
         var clip:Sprite = new Sprite();
         clip.graphics.beginFill(0x000000);
         clip.graphics.drawRect(0, 0, 50, 50);
         clip.graphics.endFill();
         addChild(clip);
         addEventListener(MouseEvent.CLICK, lanzaEvento);
      }
      private function lanzaEvento(e:MouseEvent):void
      {
         dispatcher = ClaseDispatcher.getInstancia();
         dispatcher.dispatchEvent(new Event(ClaseDispatcher.CLASEA_CLICK));
      }
   }
}


Código :

package 
{
   import flash.display.Sprite;
   import flash.events.Event;
   //
   public class ClaseB extends Sprite
   {
      private var dispatcher:ClaseDispatcher;
      //
      public function ClaseB()
      {
         dispatcher = ClaseDispatcher.getInstancia();
         dispatcher.addEventListener(ClaseDispatcher.CLASEA_CLICK,detectaEvento);
      }
      private function detectaEvento(e:Event):void
      {
         trace("Detecto el ClaseA click");
      }
   }
}


Y eso es todo. :cool:

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate