« Noviembre 2006 | Inicio | Febrero 2007 »

Diciembre 28, 2006

Cosas que el código no hace (aunque las haga en las películas)

Bastante divertido. Creo. Sobre todo el punto 8.

Diciembre 12, 2006

Novedades de AS3 (IV): Gestión de eventos

Otra de las novedades en AS3 está en el nuevo modelo de eventos. En este post no vamos a realizar una discusión muy profunda sobre el modelo de eventos ni sobre la forma de implementar la Cadena de Responsabilidad en los objetos con representación gráfica.

Simplemente, vamos a ver cómo se pueden emitir eventos, y cómo se deben escuchar los mismo.

La arquitectura es muy sencilla. Cualquier subclase de flash.events.EventDispatcher puede emitir eventos, eventos que realmente son instancias de flash.events.Event o de alguna de sus posibles subclases, y que serán escuchados por funciones o métodos de clases que hayan sido previamente registradas como listeners del evento en cuestión.

Como siempre, lo más sencillo es un ejemplo. En primer lugar, voy a construir una clase, que extenderá a flash.events.EventDispatcher, y que por tanto, tendrá la capacidad de emitir eventos. Escribiré también una función en la línea de tiempo principal de un swf, que registraré para que escuche el evento emitido por la clase anteriormente citada.


package
{
	import flash.events.*
	
	public class EventNation extends EventDispatcher
	{
		public static const EVENT_NAME: String = "particularEvent";
		
		function EventNation( )
		{
			trace( "EventNation.constructor" );
		}
		
		public function fireEvent( )
		{
			trace( "previo a dispatchEvent" );
			dispatchEvent( new Event( EVENT_NAME ) );
		}
	}
	
}

El método fireEvent es el encargado de la construcción del evento y de su lanzamiento. Para ello, se crea una instancia de flash.events.Event, pasando en el constructor de la misma el nombre del evento.

En la línea de tiempo principal, hay que declarar una función y registrarla como listener del evento.

import flash.events.*

var myVar: EventNation = new EventNation( );


function eventHandler( event: Event )
{
trace( "evento recibido " + event.toString( ) );
trace( "tipo dle evento " + event.type );
}

myVar.addEventListener( EventNation.EVENT_NAME, eventHandler );

Y finalmente, lanzar el evento:


myVar.fireEvent( );

Sencillo. El problema viene cuando en el evento emitido se quiere encapsular también algún parámetro más, específico del evento. En esos casos, la solución pasa por subclasificar Event, añadiendo a la subclase cualquier implementación específica (parámetros, cálculos, lo que sea).

Como ya vimos en un post anterior, en un paquete se puede declarar más de una clase, así pues, por intentar mantener la cohesión máxima, voy a declarar el nuevo evento en el mismo paquete en el que está la clase que lo va a emitir.

	class CustomEvent extends Event
	{
		public var param: String;
		
		function CustomEvent( msg: String )
		{
			super( msg );
			trace( "MyEvent.constructor" );
			
			param = "CustomEvent";
		}
		
		public override function toString( ): String
		{
			return "CustomEvent extends param: " + param + " -- " + super.toString( );
		}
	}

Y por tanto, a la hora de lanzar el evento, el método fireEvent de la clase EventNation será:

public function fireEvent( )
{
	trace( "previo a dispatchEvent" );
	dispatchEvent( new CustomEvent( EVENT_NAME ) );//Para pasar parámetros
	//dispatchEvent( new Event( EVENT_NAME ) );
}

El código completo del package:


package
{
import flash.events.*

public class EventNation_2 extends EventDispatcher
{
public static var EVENT_NAME: String = "particularEvent";

function EventNation_2( )
{
trace( "Myclass.constructor" );
}

public function fireEvent( )
{
trace( "previo a dispatchEvent" );
dispatchEvent( new CustomEvent( EVENT_NAME ) );//Para pasar parámetros
//dispatchEvent( new Event( EVENT_NAME ) );
}
}

class CustomEvent extends Event
{
public var param: String;

function CustomEvent( msg: String )
{
super( msg );
trace( "MyEvent.constructor" );

param = "CustomEvent";
}

public override function toString( ): String
{
return "CustomEvent extends param: " + param + " -- " + super.toString( );
}
}
}

Y en la línea de tiempo principal se podrá obtener el valor del parámetro extra:


import flash.events.*

var myVar: EventNation_2 = new EventNation_2( );


function eventHandler( event: Event )
{
trace( "evento recibido " + event.toString( ) );
trace( "tipo dle evento " + event.type );
trace( "parametro custom " + event.param );
}

myVar.addEventListener( EventNation.EVENT_NAME, eventHandler );
myVar.fireEvent( );

De esta forma, se solucionan los problemas en la implementación del modelo de eventos de AS2. Ya no son necesarias las delegaciones, menos aún las mezclas de delegación y hack para poder emitir eventos con parámetros. La forma de manejar el problema es muy sencilla y clara, poco propensa a errores. Como debe ser.