PixLib - Understanding the basis of the framework
readed 11016 timesThis 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)
Sources
Sources File and Tweaked class (Size: 28.5 KB)
Pixlib Framework r35 Download the framework (Size: 369.2 KB)
Download the sources for this tutorial.
Sources
Download the tutorial sources (Size: 49.8 KB)
This is a template for futur projects you will do.
Pixlib Template
Download the template (Size: 22.6 KB)
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
-
import net.webbymx.projects.tutorial01.Application;
-
var apz : Application = new Application( this );
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

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:
-
// 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
-
**************************************************************************** */
-
}
Ok what is it doing?
-
container.__proto__ = this.__proto__;
-
container.__constructor__ = Application;
-
this = container;
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
-
Logger.getInstance().addLogListener( LuminicTracer.getInstance() );
Second we are creating our views from the MovieClip that we have attached on the stage
-
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 );
Third, we are creating the model
-
var mClock : ModelClock = new ModelClock();
and setting the views as listener of this model, so then when a model will broadcast an event the views will react to it
-
mClock.addListener( vDigital );
-
mClock.addListener( vAnalog );
-
mClock.addListener( vTools );
Finally we are creating the FrontController, that will listen to the XEventBroadcaster and call the command associated to the event
-
Controller.getInstance( XEventBroadcaster.getInstance() );
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
-
/**
-
* 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() {}
-
}
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
-
// 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
-
**************************************************************************** */
-
-
}
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
-
function ViewTools( mc : MovieClip ) {
-
super( ViewList.VIEW_TOOLS, mc );
-
_init();
-
}
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
-
ViewTool( MovieClipHelper.getMovieClipHelper( ViewList.ViewTool ) )
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
-
ViewTool.view.txt_color
I prefer setting up private variables in my class that refer to those assets.
-
_txtColor = view.txt_color;
-
_btnStart = view.btn_start;
-
_btnStop = view.btn_stop;
-
_btnColor = view.btn_color;
Finally we are setting up the mouse event for the button
-
_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) );
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
-
_btnStart.onRelease = function () {
-
XEventBroadcaster.getInstance().broadcastEvent( new BasicEvent( EventList.START_CLOCK ) );
-
}
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.
-
// 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