Blog

PixLib – Understanding the basis of the framework

This tutorial is provided to give you the basis to be able to use the so good PixLib framework made by Francis Bourre. You should know at least what is a MVC pattern and a Command pattern.

Usually, using a MVC, each view will have a controller that will update the model ( if needed ) and any views that need to be changed.
This can be achieved in the PixLib library using the class in com.bourre.mvc. But this tutorial will not deal with this “usual” MVC pattern.

Francis add to his framework something really flexible, called the FrontController. This controller is receiving events from any views and then call the Command associated to it.
You’re code is then really clean and pratical: one class = one command so your code for an action can be found really easilly, plus you can see all the actions that could be executed looking at the FrontController code, everything is in there.
You will not look in X classes to try to find the code that do this particular action, you will go straight to the goal.

Here is a basic scheme of it

So enought blabla let’s have a look at it. I will explain what is what and what is doing what as we will see the examples. We will try to build a clock with analog and digital display.

Download the last frameword (revision 35)
[Download id not defined]

[Download id not defined]

Download the sources for this tutorial.
[Download id not defined]

This is a template for futur projects you will do.
[Download id not defined]

 

I. The FLA

First check the fla. I have created 3 MovieClips. One for the digital clock, one for the analog and one for the toolbar where the buttons to stop and start the clock are. Those MovieClip will be used as the views ( interfaces )
In the first ( and only ) frame of the fla you have this code
[as]
import net.webbymx.projects.tutorial01.Application;
var apz : Application = new Application( this );
[/as]
What we are doing here is importing the Application.as wich is the entry point of our code, and creating an instance of it using the _root or _level0. We will see later what is it for.

 

II. The Code

First let see how a project using the PixLix Framework is structured.
To help you, I’ve done a template for it. You will find the basic files needed to develop an application with the pixlib library using the MVCC ( MVC + COMMAND ) pattern.

So here is the structure
PixLib Project Structure

and the quick explanation

  • commands: contain all your classes implementing the com.bourre.commands.Command interface. Will contain as well the FrontController.
  • events: contain all your classes defining a new type of event ( extending the BasicEvent ). Will contain as well your custom EventBroadcaster class and the EventList class which is only an enumeration of all the events existing.
  • models: contain the model and the ModelList
  • services: will contain every classes that deal with exterior datas ( like server, xml, … )
  • uis: contain all classes that define your User Interfaces
  • views: all the classes that will extend the MovieClipHelper or ViewHelper classes and that will be link to a MovieClip. Contain as well the ViewList class
  • vos: classes to define custom value object
  • Application.as: this is the main class of your application that will create everything
 

a. Application

So ok, let’s have a look now at the Application.as class:
[as]
// Debug
import com.bourre.log.Logger;
import com.bourre.log.LogLevel;
import com.bourre.utils.LuminicTracer;

// Views
import net.webbymx.projects.tutorial01.views.ViewAnalog;
import net.webbymx.projects.tutorial01.views.ViewDigital;
import net.webbymx.projects.tutorial01.views.ViewTools;

// Controller
import net.webbymx.projects.tutorial01.commands.Controller;

// Models
import net.webbymx.projects.tutorial01.models.ModelClock;

// Personnal EventBroadcaster
import net.webbymx.projects.tutorial01.events.XEventBroadcaster;

class net.webbymx.projects.tutorial01.Application
extends MovieClip {
/* ****************************************************************************
* PRIVATE VARIABLES
**************************************************************************** */

/* ****************************************************************************
* CONSTRUCTOR
**************************************************************************** */
function Application(container) {
// the movieclip is transtyped as a application object
container.__proto__ = this.__proto__;
container.__constructor__ = Application;
this = container;

// init the object
_init();
}

/* ****************************************************************************
* PRIVATE FUNCTIONS
**************************************************************************** */
/**
* Init the Application
* @param Void
*/
private function _init( Void ) : Void {
// init the debugger
Logger.getInstance().addLogListener( LuminicTracer.getInstance() );

// Instanciating the views
var digital : MovieClip = this.attachMovie( “mc_digital”, “mc_digital”, 0 );
var vDigital : ViewDigital = new ViewDigital ( digital );

var analog : MovieClip = this.attachMovie( “mc_analog”, “mc_analog”, 1 );
var vAnalog : ViewAnalog = new ViewAnalog ( analog );

var tools : MovieClip = this.attachMovie( “mc_tools”, “mc_tools”, 2 );
var vTools : ViewTools = new ViewTools ( tools );

// create the model
var mClock : ModelClock = new ModelClock();

// the views are listening to the model
mClock.addListener( vDigital );
mClock.addListener( vAnalog );
mClock.addListener( vTools );

// init the controller with our custom EventBroadcaster class
Controller.getInstance( XEventBroadcaster.getInstance() );
}

/* ****************************************************************************
* PUBLIC FUNCTIONS
**************************************************************************** */
/* ****************************************************************************
* GETTER & SETTER
**************************************************************************** */
}
[/as]
Ok what is it doing?
[as num=33]
container.__proto__ = this.__proto__;
container.__constructor__ = Application;
this = container;
[/as]
Well, first we are transtyping the “container” ( pass as an argument ) which is here ( and in most of the case ) the _root / _level0 of your fla, as an Application object. As you can see our Application.as class is inheriting the MovieClip, so we are keeping the MovieClip properties and methods.

We are then calling the _init() function which will set up everything.

First we are defining the Debugger
[as num=51]Logger.getInstance().addLogListener( LuminicTracer.getInstance() );[/as]
Second we are creating our views from the MovieClip that we have attached on the stage
[as num=54]
var digital : MovieClip = this.attachMovie( “mc_digital”, “mc_digital”, 0 );
var vDigital : ViewDigital = new ViewDigital ( digital );

var analog : MovieClip = this.attachMovie( “mc_analog”, “mc_analog”, 1 );
var vAnalog : ViewAnalog = new ViewAnalog ( analog );

var tools : MovieClip = this.attachMovie( “mc_tools”, “mc_tools”, 2 );
var vTools : ViewTools = new ViewTools ( tools );
[/as]
Third, we are creating the model
[as num=70]var mClock : ModelClock = new ModelClock();[/as]
and setting the views as listener of this model, so then when a model will broadcast an event the views will react to it
[as num=67]
mClock.addListener( vDigital );
mClock.addListener( vAnalog );
mClock.addListener( vTools );
[/as]
Finally we are creating the FrontController, that will listen to the XEventBroadcaster and call the command associated to the event
[as num=72]Controller.getInstance( XEventBroadcaster.getInstance() );[/as]

Now we will go through each class to see what they are doing.

 

b. The ViewList, the Views and how to use it

First the ViewList. This class is just an enumeration of all the views ( class ) you can have in you application. As flash is not providing enumeration type, this is a way to do it…
Here is the class
[as]
/**
* listing of the views
*/
class net.webbymx.projects.tutorial01.views.ViewList {
/* ****************************************************************************
* PUBLIC STATIC VARIABLES
**************************************************************************** */
public static var VIEW_ANALOG : String = “view_analog”;
public static var VIEW_DIGITAL : String = “view_digital”;
public static var VIEW_TOOLS : String = “view_tools”;

/* ****************************************************************************
* CONSTRUCTOR
**************************************************************************** */
private function ViewList() {}
}
[/as]

 

Then, let check the view ViewTool, because in the small application we are doing it’s the one using all the basic functionalities.
So first the full code
[as]
// Debug
import com.bourre.log.Logger;
import com.bourre.log.LogLevel;

// Delegate
import com.bourre.commands.Delegate;

// Event Broadcasting
import com.bourre.events.IEvent;
import com.bourre.events.BasicEvent;
import com.bourre.events.EventType;
import net.webbymx.projects.tutorial01.events.EventList;
import net.webbymx.projects.tutorial01.events.XEventBroadcaster;

// MovieClipHelper
import com.bourre.visual.MovieClipHelper;

// list of Views
import net.webbymx.projects.tutorial01.views.ViewList;

class net.webbymx.projects.tutorial01.views.ViewTools
extends MovieClipHelper {
/* ****************************************************************************
* PRIVATE VARIABLES
**************************************************************************** */
// Assets
private var _txtColor : TextField;
private var _btnStart : MovieClip;
private var _btnStop : MovieClip;
private var _btnColor : MovieClip;

/* ****************************************************************************
* CONSTRUCTOR
**************************************************************************** */
function ViewTools( mc : MovieClip ) {
super( ViewList.VIEW_TOOLS, mc );
_init();
}

/* ****************************************************************************
* PRIVATE FUNCTIONS
**************************************************************************** */
/**
* Init the view
* @param Void
*/
private function _init( Void ) : Void {
// Position the MovieClip
view._x = 33;
view._y = 180;

// init var, assets, events, …
_txtColor = view.txt_color;
_btnStart = view.btn_start;
_btnStop = view.btn_stop;
_btnColor = view.btn_color;

// Mouse events
_btnStart.onRelease = Delegate.create( this, _fireEvent, new BasicEvent( EventList.START_CLOCK ) );
_btnStop.onRelease = Delegate.create( this, _fireEvent, new BasicEvent( EventList.STOP_CLOCK ) );
_btnColor.onRelease = Delegate.create( this, _fireEvent, new BasicEvent( EventList.CHANGE_CLOCK_COLOR) );

disableStart();

}

/**
* Broadcast the event
* @usage _fireEvent( new BasicEvent( EventList.MYTYPE, Object ) );
* @param e
*/
private function _fireEvent( e : IEvent ) : Void {
XEventBroadcaster.getInstance().broadcastEvent( e );
}

/* ****************************************************************************
* PUBLIC FUNCTIONS
**************************************************************************** */
public function disableStart( Void ) : Void {
_btnStop.enabled = true;
_btnStop._alpha = 100;
_btnStart.enabled = false;
_btnStart._alpha = 60;
}

public function disableStop( Void ) : Void {
_btnStop.enabled = false;
_btnStop._alpha = 60;
_btnStart.enabled = true;
_btnStart._alpha = 100;
}

/* ****************************************************************************
* GETTER & SETTER
**************************************************************************** */

}
[/as]

Now let’s see how it works.
A view is an interface. The code in this class only act on the visual aspect. Your view ( class ) is so associated to a visual object ( a MovieClip ). Here, we are not using the inheritance as we have done for the Application, but the composition. Our ViewTool has a property call view where the reference of the MovieClip will be stored.
Looking at the constructor
[as num=35]
function ViewTools( mc : MovieClip ) {
super( ViewList.VIEW_TOOLS, mc );
_init();
}
[/as]
we can see that we are calling the super class ( MovieClipHelper ) constructor. This one is storing the name of your view and the reference of it in a Map ( array associating object ), and the reference of your MovieClip in the property view.

Why that?
The MovieClipHelper class has a static public function called getMovieClipHelper. This function return the view ( class ) wanted. You’re using it like that
[as]ViewTool( MovieClipHelper.getMovieClipHelper( ViewList.ViewTool ) )[/as]
This mean that you can access your view from anywhere and thus have control on your MovieClip ( with the view properties or by using public functions )

Ok for this part. Now we are looking at the code in the _init function.
Instead of accessing the assets on the MovieClip by doing
[as]ViewTool.view.txt_color[/as]
I prefer setting up private variables in my class that refer to those assets.
[as num=54]
_txtColor = view.txt_color;
_btnStart = view.btn_start;
_btnStop = view.btn_stop;
_btnColor = view.btn_color;
[/as]

 

Finally we are setting up the mouse event for the button
[as num=60]
_btnStart.onRelease = Delegate.create( this, _fireEvent, new BasicEvent( EventList.START_CLOCK ) );
_btnStop.onRelease = Delegate.create( this, _fireEvent, new BasicEvent( EventList.STOP_CLOCK ) );
_btnColor.onRelease = Delegate.create( this, _fireEvent, new BasicEvent( EventList.CHANGE_CLOCK_COLOR) );
[/as]
Each button will dispatch an event ( from the enumeration of the EventList class ).
Here I’m using the Delegate way ( cleaner ) but you could use
[as]
_btnStart.onRelease = function () {
XEventBroadcaster.getInstance().broadcastEvent( new BasicEvent( EventList.START_CLOCK ) );
}
[/as]

Then we have 2 public function that a command will call to enable/disable the stop/start buttons

 

c. The ModelList and the ModelClock

The ModelList is like the ViewList. It’s just a class listing variables, to emulate the enum ( enumeration ) type that doesn’t exist in flash. So in this class we will list all the models name we are using in our application ( here one only ). Yes actually you can create more than one model if you need it ( eg to separate different logic ). Anyway I never done it yet…

The ModelClock is a class storing the code for the logic, everything that’s “behind the scene” to make your application working. In our example it will store the code to tick every seconds.
[as]
// Debug
import com.bourre.log.Logger;
import com.bourre.log.LogLevel;

// Model
import com.bourre.core.Model;

// Import the model list
import net.webbymx.projects.tutorial01.models.ModelList;

// Broadcasting event
import com.bourre.events.EventType;
import com.bourre.events.BasicEvent;

class net.webbymx.projects.tutorial01.models.ModelClock
extends Model {

/* ****************************************************************************
* PRIVATE STATIC VAR
**************************************************************************** */
private static var CLOCK_TICK : EventType = new EventType( “onClockTicking” );

/* ****************************************************************************
* PRIVATE VAR
**************************************************************************** */
private var _siTick : Number;
private var _dDate : Date;

/* ****************************************************************************
* CONSTRUCTOR
**************************************************************************** */
function ModelClock() {
super( ModelList.MODEL_CLOCK);
_startTicking();
}

/* ****************************************************************************
* PRIVATE FUNCTIONS
**************************************************************************** */
private function _startTicking( Void ) : Void {
// set up the date actual date and time
_dDate = new Date();
_tick();
_siTick = setInterval( this, “_tick”, 1000 );
}

private function _stopTicking( Void ) : Void {
clearInterval( _siTick );
}

private function _tick( Void ) : Void {
// add one second to the date object
_dDate.setSeconds( _dDate.getSeconds() + 1 );

// create the object time which will be sent during the broadcasting
var oTime = new Object();
oTime.seconds = _dDate.getSeconds().toString();
oTime.minutes = _dDate.getMinutes().toString();
oTime.hours = _dDate.getHours().toString();

if ( oTime.hours.length == 1 ) oTime.minutes = “0”+oTime.hours;
if ( oTime.minutes.length == 1 ) oTime.minutes = “0”+oTime.minutes;
if ( oTime.seconds.length == 1 ) oTime.seconds = “0”+oTime.seconds;

// Broadcasting the event to the view listening to the model ( init in the Application.as class )
_oEB.broadcastEvent( new BasicEvent( CLOCK_TICK, oTime ) );
}
/* ****************************************************************************
* PUBLIC FUNCTIONS
**************************************************************************** */
/**
* called by the startClock command
* @param Void
*/
public function startClock( Void ) : Void {
_startTicking();
}

/**
* called by the stopClock command
* @param Void
*/
public function stopClock( Void ) : Void {
_stopTicking();
}

/* ****************************************************************************
* GET & SET
**************************************************************************** */

}
[/as]
In the constructor we are doing the same as for the view. I mean here that we are sending to the constructor the name of the model ( retreived from the ModelList ).
The constructor will register in a Map the name of the model and its reference.
Then you will be able to retreive your model like
[as]ModelClock( Model.getModel( ModelList.MODEL_CLOCK ) )[/as]

As you can see line 21, we are creating ( as in the EventList ) a list of Event that the ModelClock will dispatch.
Here it’s a bit different. The Model will dispatch the event and the View listening to the model will execute the function given in the EventType param, so here the “onClockTicking”.
So in our model, every seconds this “onClockTicking” will be dispatch. The view will receive this event and will execute the function, making the needle go to the next second or the number to change.
You can see as well that the model as 2 public function, to start and stop the clock. Those function will be called from a command. Don’t forget that a command can call function on Model AND Views. Check the StartCommand eg.

 

d. The EventList and the XEventBroadcaster

The EventList is like the ViewList. It’s just a class listing variables, to emulate the enum ( enumeration ) type that doesn’t exist in flash. So in this class we will list all the events name we are using in our application.

The XEventBroadcaster is a custom EventBroadcaster. By default in the PixLib framework you have a default EventBroadcaster that is implicitly created. I prefer using a custom one, thus if you are creating complexe application/website that are using modules ( so more than one EventBroadcaster ) it will not be the mess. Each modules will have its own and events will not be sent to FrontControllers that shouldn’t received it. Remember that the FrontController is listening to the EventBroadcaster. That’s why in the Application.as we have created a new Controller that is listening to the XEventBroadcaster… Pfff, a bit long this one…

 

e. The FrontController

The FrontController is pretty simple.
[as]
// Debug
import com.bourre.log.Logger;
import com.bourre.log.LogLevel;

// Type
import com.bourre.core.HashCodeFactory;
import com.bourre.events.FrontController;

// Commands and Event list
import net.webbymx.projects.tutorial01.commands.*;
import net.webbymx.projects.tutorial01.events.EventList;

class net.webbymx.projects.tutorial01.commands.Controller
extends FrontController {

/* ****************************************************************************
* PRIVATE STATIC VAR
**************************************************************************** */
private static var _oI : Controller;

/* ****************************************************************************
* PUBLIC STATIC FUNCTIONS
**************************************************************************** */
public static function getInstance( myDispatcher ) : Controller {
if (!_oI) _oI = new Controller( myDispatcher );
return _oI;
}

/* ****************************************************************************
* CONSTRUCTOR
**************************************************************************** */
private function Controller( myDispatcher ) {
super( myDispatcher );
_oI = this;
_init();
}

/* ****************************************************************************
* PUBLIC FUNCTIONS
**************************************************************************** */
/**
* Push the event in the controller and link them to a command
* @param Void
*/
private function _init( Void ) : Void {
push ( EventList.START_CLOCK , new StartClock() );
push ( EventList.STOP_CLOCK, new StopClock() );
}

/**
* Return the instance id
* @return
*/
public function toString() : String {
return ‘net.webbymx.projects.echo.commands.Controller’ + HashCodeFactory.getKey( this );
}
}
[/as]
The FrontController is a singleton. It’s structure will always be the same. You will edit then the _init() function where you will add pairs of event/command.
The FrontController will listen the XEventBroadcaster for events. When an event is trigered it will check in the array for this event and will call the command associated to it.

 

f. The Commands

So we’ve seen that the FrontController for an event is creating a new instance of a command. The FrontController will call as well the execute function of the specified command.
Let’s take the StartClock command
[as]
// Debug
import com.bourre.log.Logger;
import com.bourre.log.LogLevel;

// Implement
import com.bourre.commands.Command;

// Hash
import com.bourre.core.HashCodeFactory;

// Type
import com.bourre.events.IEvent;

// Model
import com.bourre.core.Model;
import net.webbymx.projects.tutorial01.models.ModelClock;
import net.webbymx.projects.tutorial01.models.ModelList;

// Views
import com.bourre.visual.MovieClipHelper;
import net.webbymx.projects.tutorial01.views.ViewList;
import net.webbymx.projects.tutorial01.views.ViewTools;

class net.webbymx.projects.tutorial01.commands.StartClock
implements Command {

/* ****************************************************************************
* CONSTRUCTOR
**************************************************************************** */
function StartClock() {}

/* ****************************************************************************
* PUBLIC FUNCTIONS
**************************************************************************** */
/**
* This called by the FrontController when a event associated to it is triggered
* @param e
*/
public function execute( e : IEvent ) : Void {
// execute the stopClock method of the ModelClock object
// here the command name is the same as the function name, BUT it could be different
ModelClock( Model.getModel( ModelList.MODEL_CLOCK ) ).startClock();

// disable the start button on the ViewTools and enable the stop button
ViewTools( MovieClipHelper.getMovieClipHelper( ViewList.VIEW_TOOLS ) ).disableStart();
}

public function toString() : String {
return ‘net.webbymx.projects.tutorial01.commands.StartClock’ + HashCodeFactory.getKey( this );
}

}
[/as]
You can see the execute function. This function has one argument which is an object implementing the IEvent. It could be then a BasicEvent or any type of event you will create.
Then you can call a public function of a view using
[as]YourViewType( MovieClipHelper.getMovieClipHelper( YourViewList.YourView ) ).yourFunction ( args )[/as]
or of a model using
[as]YourModelType( Model.getModel( ModelList.MyModel ) ).yourFunction( args )[/as]
You can see here that we are using strong typing ( YourViewType( .. ) YourModelType( … ) ) . Thus eg in FlashDevelop you will get all the public function of this class in the IDE.

Conclusion

So we’ve seen here how to use the basic classes to create a application using the MVC+Command pattern.
It could look hard at the begining but it’s really simple as soon as you get how is the data’s flow.
Look carefully at the schema. Views are broadcasting ( via XEventBroadcaster ) events to the FrontController. This one is calling the command associated to that event. A command can then call public function on a View, using
[as]MyViewType( MovieClipHelper.getMovieClipHelper( ViewList.MyView ) ).aFunction();[/as]
or on a Model using
[as]MyModelType( Model.getModel( ModelList.MyModel ) ).aFunction();[/as]
Finally a Model can disptach event to the views that are listening to it…

Voila, this is the end of this tutorial. I hope it helps you a bit understanding the architecture of the framework.
Soon I hope I’ll have time to post tutorials of specific classes, like the ConfigLoader that helps you loading configuration from a XML file and let you parsed it and create custom object out of it…

C ya 🙂

[edit]
Thx to Sventunus who has pointed out a typo error in the code.
Sources are up to date
[/edit]

  • micmac88

    Fantastique tuto ! so useful. merci !

  • micmac88

    Fantastique tuto ! so useful. merci !

  • Bob

    Very useful tutorial.

    If you find the files pixlib_template.zip & tutorial-pixlib-01.zip
    could you upload them again.

    Thanks

  • Bob

    Very useful tutorial.

    If you find the files pixlib_template.zip & tutorial-pixlib-01.zip
    could you upload them again.

    Thanks

  • Bob

    Thanks for making the source files available again. Very good to have a code base for an AS2 project I have to work on. Looks like Cairngorm in places which helps me understand it.

  • Bob

    Thanks for making the source files available again. Very good to have a code base for an AS2 project I have to work on. Looks like Cairngorm in places which helps me understand it.

  • Ganesh Lal Bairwa

    I found this tutorial very simple presentation of a complex framework. I need to work on XmlToObject. If you have any tutorial then plz give me link.

    thanks for your nice effort.

  • Ganesh Lal Bairwa

    I found this tutorial very simple presentation of a complex framework. I need to work on XmlToObject. If you have any tutorial then plz give me link.

    thanks for your nice effort.

  • Pingback: Pixlib | dehash()

  • Thank you for sharing this!

  • Thank you for sharing this!