[PPC] AplicaciÛn del modelo-vista-controlador a una aplicaciÛn para PocketPC
Pues el caso es que habÌa quedado con unos amigos para jugar al scalextric, pero alguien se acordÛ de que el cuentavueltas no funcionaba, asÌ que pensÈ: "podemos usar un l·piz y un papel, seguro, pero °Èste es un trabajo para mi pocket pc!".
AsÌ que hice un cuentavueltas. …ste es el resultado final:

La aplicaciÛn es muy simple. Pero la he implementado utilizando el modelo-vista-controlador, y por probar, usando los componentes de IU est·ndares de flash. No he utilizado los propios del PocketPC CDK porque, aunque ya ha pasado un aÒo desde la ˙ltima aplicaciÛn que hice para PocketPC, todavÌa no se me ha pasado el susto. Dicho de otro modo, no es que sean demasiado eficaces.
Antes de comenzar, una pequeÒa nota al margen. Utilizo mi propio sistema de eventos. Ya lo he utilizado con anterioridad en otros posts, pero lo he incluÌdo en la descarga con las fuentes de esta aplicaciÛn. B·sicamente, consiste en una clase base que deben extender todas las que sean emisoras de eventos ( EventSource ), y que implementa un interfaz llamado IEventRegister. TambiÈn utilizo un HashMap, que esta incluido en el zip
Pues al ataque. Los componentes y el textfield para la salida est·n colocados en el stage. Esos son los gr·ficos que estar·n controlados por la vista ( CounterView.as )
import mx.utils.Delegate;
import net.designnation.lapcounter.LapCounterController
class net.designnation.lapcounter.CounterView
{
private var timeline : MovieClip;
private var controllerVal : LapCounterController;
function CounterView( timeline: MovieClip )
{
this.timeline = timeline;
this.initView( );
}
private function initView( )
{
var viewRef: CounterView = this;
this.timeline.resetButton.label= "Reset";
this.timeline.resetButton.addEventListener( "click",
Delegate.create( this, onResetBTClicked ) );
this.timeline.countButton.label = "Tap me, please!";
this.timeline.countButton.addEventListener( "click",
Delegate.create( this, onCountBTClicked ) );
this.timeline.switchCB.setStyle( "color", 0xFFFFFF );
this.timeline.switchCB.label="increment";
this.timeline.switchCB.addEventListener( "click",
Delegate.create( this, onCheckBoxClicked ) );
this.timeline.switchCB.selected = true;
}
public function set controller( controllerRef: LapCounterController )
{
this.controllerVal = controllerRef;
}
public function onCounterChanged( param: Object )
{
this.timeline.result.text = param.value;
}
public function onCountBTClicked( )
{
this.controllerVal.screenClicked( );
}
public function onResetBTClicked( )
{
this.controllerVal.reset( );
}
public function onCheckBoxClicked( )
{
this.controllerVal.incFlagChanged( );
}
}
Esta clase asigna las etiquetas a los botones y al checkbox, y utiliza la clase Delegate para asignar los manejadores de los eventos de dichos componentes. Por tanto, cuando se haga click en countButton ( el botÛn grandote ), el evento ser· escuchado por el mÈtodo "onCountBTClicked" the la clase CounterView.
Hay un mÈtodo para actualizar la salida por pantalla ( asignando el valor de un campo de texto llamado result ), y tres mÈtodos para manejar las acciones del usuario ( uno por componente, gracias a la delegaciÛn ). Estos mÈtodos ejecutan a su vez un mÈtodo p˙blico del controlador
Ya sÈ que la vista puede, y probablemente deba, atacar directamente al modelo para que Èste cambie su estado, pero eso no es algo que me guste mucho. Yo prefiero, siempre que sea posible, hacerlo a travÈs del controlador
Pero, ø dÛnde est· el controlador ?. Pues se construye en el primer frame del fla, mediante el siguiente cÛdigo:
import net.designnation.lapcounter.*
var controller: LapCounterController = new LapCounterController( new CounterView( this ) );
Por tanto, se inicializa el controlador y se le pasa una instancia de la vista. Veamos el controlador con m·s detalle.
import net.designnation.lapcounter.*
class net.designnation.lapcounter.LapCounterController
{
private var lapCounter : ILapCounterActions;
private var counterView : CounterView;
private var timeline : MovieClip;
function LapCounterController( view: CounterView )
{
this.counterView = view;
this.counterView.controller = this;
this.initCounter( );
}
private function initCounter( )
{
this.lapCounter = new LapCounter( );
this.lapCounter.registerEvent( this.counterView, "onCounterChanged" );
}
public function screenClicked( )
{
this.lapCounter.addLap( );
}
public function incFlagChanged( )
{
this.lapCounter.setInc( );
}
public function reset( )
{
this.lapCounter.reset( );
}
}
El controlador tiene una referencia a la vista, y es el encargado de crear el modelo ( LapCounter ). No mantiene una referencia al modelo como tal, sino al interaz del mismo ( ILapCounterActions ). Pero veremos el modelo m·s tarde
Cuando se crea el modelo, el modelo registra a la vista como event listener del modelo. Por tanto, cuando Èste cambie su estado ( los datos que contiene ), emitir· un evento que ser· escuchado directamente por la vista.
TambiÈn hay tres mÈtodos ( screenClicked, incFlagChanged, and reset ), que son los que utiliza la vista para comunicarse con el modelo
Y, por ˙ltimo, llegamos al modelo ( LapCounter.as )
import net.designnation.events.EventSource
import net.designnation.lapcounter.ILapCounterActions
class net.designnation.lapcounter.LapCounter extends EventSource implements ILapCounterActions
{
private var actualLaps : Number;
private var incFlag : Boolean;
function LapCounter( )
{
this.actualLaps = 0;
this.incFlag = true;
}
public function addLap( )
{
var multiplier: Number = ( this.incFlag )? 1: -1;
this.actualLaps+= 1* multiplier;
if ( this.actualLaps< 0 ) this.actualLaps = 0;
updateView( );
}
private function updateView( )
{
fireEvent( "onCounterChanged", { value: this.actualLaps } );
}
public function setInc( )
{
this.incFlag = !this.incFlag;
}
public function reset( )
{
this.actualLaps = 0;
updateView( );
}
}
Esta clase extiende EventSource ( para heredar asÌ el manejo de eventos ), e implementa un interfaz ( ILapCounterActions ). Ese interfaz ser· la referencia que tiene el controlador del modelo. De este modo, se podrÌa cambiar el modelo, sin afectar al resto de la aplicaciÛn ( siempre y cuando el nuevo modelo tambiÈn implemente ese interfaz, claro ). Este interfaz extiende a su vez del interfaz de registro de eventos.
El modelo no es muy complejo ( la aplicaciÛn tampoco ). Simplemente maneja un contador, y una bandera para saber si el contador debe incrementarse o decrementarse. TambiÈn hay un mÈtodo para actualziar la vista ( emitiendo el evento pertinente ).
Y eso es todo. Simplemente hay que publicar la aplicaciÛn como flash 6, crear un html para contenerla, y °a jugar al scalextric!
Y por supuesto, el cÛdigo fuente: est· aquÌ