How to create a new Flash application with the ASAP Framework
Accompanying demos:
Simple Demo (event handling) and
Simple Application Demo (movie handling).
See
ASAP Movie Management for an introduction to multi-movie projects.
The basics
- Download the latest framework from Sourceforge. Example:
asap_framework_0.94.zip
- Unzip the framework in a clearly named folder (preferably containing the version number of the framework). Example:
D:/Projects/ASAP/asap_framework_0.94/
- Create a new Flash file
- Save the
fla in a new folder
- In the same folder, create a folder and name it
scripts
- Add the full path to the framework to the classpath. In this case:
D:/Projects/ASAP/asap_framework_0.93/
- Also add the scripts folder to the classpath, like this:
./scripts/
- Create a class called
AppController that extends the class org.asapframework.management.movie.LocalController as found in the framework:import org.asapframework.management.movie.LocalController;
class AppController extends LocalController {
}
- In this class, create the following entry point
public static function main (inTimeline:MovieClip) : Void {
var controller:AppController = new AppController(inTimeline);
inTimeline.controller = controller;
controller.start();
}
- Create the constructor of the AppController class as follows:
public function AppController (inTimeline:MovieClip) {
super(inTimeline);
}
- The whole class then looks like this:
import org.asapframework.management.movie.LocalController;
class AppController extends LocalController {
public function AppController (inTimeline:MovieClip) {
super(inTimeline);
}
public static function main (inTimeline:MovieClip) : Void {
var controller:AppController = new AppController(inTimeline);
inTimeline.controller = controller;
controller.start();
}
}
- On the first frame of the timeline, add the following code:
AppController.main(this);
- Create the rest of the application, with the AppController class as top level controller of the application.
Controlling the main timeline
The AppController as created in the previous section gives you access to the timeline via either (public)
getTimeline() or the (private) property
mTimeline. To make the
AppController? instance stop the timeline from playing, you can do:
public function stopTheTimeline () : Void {
mTimeline.stop();
}
Access to movieclips on the timeline
All named movieclips on the main timeline are accessible as properties of the
timeline property. Be aware that there is no compile time check on this.
Example: A MovieClip on the timeline with the name
block_mc can be controlled from the AppController class like this:
mTimeline.block_mc._visible = false;
If a class has been attached to the movieclip, it can be cast to the right type:
var myButton:EventButton = EventButton(mTimeline.button_mc);
myButton.setSendEventOnRoll(true);
Access to the controller from lower classes
The preferred way of controlling contained objects is top-down. This means for example, that the AppController "talks" directly to the contained movieclips, and controls them. These objects, mostly ui objects, talk back to the controller via events. Good programming practice is to notify the controller of state changes of the ui object, and let the controller further deal with this – and let the ui object only do its main job: drawing itself and catching events.
Normally the controller will subscribe to events sent by contained objects in order to listen to their notifications. However, due to the nature of Flash, it isn't always possible for the controller to find the contained movieclips and subscribe to their events. Sometimes, ui objects (like buttons) need to have access to the controller of the main timeline in order to subscribe it to their events. This is typically the case for objects for which it is unknown when they will be loaded.
The main controller for a movie can be found as follows:
var lc:LocalController = MovieManager.getInstance().getNearestLocalController(this);
The parameter to the call to
getNearestLocalController() has to be of type MovieClip (if the class does not extend MovieClip, there is usually no reason to ask for the nearest controller).
This lookup method works even for deeply nested movieclips.
Example:
import org.asapframework.management.movie.MovieManager;
import org.asapframework.management.movie.LocalController;
import org.asapframework.events.Event;
import org.asapframework.ui.EventMovieClip;
class MyButton extends EventMovieClip {
public static var ON_LOADED:String = "onMyButtonLoaded";
private var mController:LocalController;
public function MyButton () {
super();
}
public function onLoad () : Void {
// get the nearest local controller from the moviemanager
mController = MovieManager.getInstance().getNearestLocalController(this);
// let the controller listen to our ON_LOADED event
addEventListener(MyButton.ON_LOADED, mController);
// notify the controller we've loaded
dispatchEvent(new Event(MyButton.ON_LOADED, this));
}
public function onUnload () : Void {
removeEventListener(ON_LOADED, mController);
}
}
Some classes in the framework add their nearest controller automatically as listener. The most used example is the EventButton class. This class, and all its derived classes, send the press, release & roll events to this controller.
Note that EventDelegate cannot be used in this case. The listener class has to check with the sending class what the literal names of the events are, and define the handler functions with the same literal names.
Event handling
Sending events
Events are handled via the dispatcher model. Any class can be enabled to dispatch events, and any object can add itself, or be added, as listener to the dispatching class instance.
The framework exposes two base classes to enable classes to dispatch events.
- For classes that do not extend MovieClip? , the base class
org.asapframework.events.Dispatcher is available. Example:import org.asapframework.events.Dispatcher;
class MyXMLLoader extends Dispatcher {
public function MyXMLLoader () {
super();
}
}
- For classes that do extend MovieClip? , the base class org.asapframework.ui.EventMovieClip is available. Example:
import org.asapframework.ui.EventMovieClip;
class MySendingMovieclip extends EventMovieClip {
public function MySendingMovieclip () {
super();
}
}
Note the call to
super() in both constructors.
Both base classes make the following methods available to the derived class:
-
public addEventListener() to add a listener to the current instance
-
public removeEventListener() to remove a listener from the current instance
-
dispatchEvent() to send events to whoever is listening
Events are instances of the framework class
org.asapframework.events.Event, or derived classes thereof.
In order to send an event that does not require extra information to be sent with the event, use the Event class:
- define public constants for the names of events to be sent. Example:
public static var ON_ALLXML_LOADED:String = "onAllXMLLoaded";
- Send the event where necessary:
dispatchEvent(new Event(DataManager.ON_ALLXML_LOADED, this));
If more information needs to be sent, create a derived event class. Also, define the name of the event(s) to be sent in this derived event class, rather than the class that sends the event, as in the previous example.
Example:
import org.asapframework.events.Event;
class ButtonEvent extends Event {
public static var ON_BUTTON_PRESSED:String = "onButtonPressed";
public var buttonName:String;
public function ButtonEvent (inType:String, inSender:MyButton, inName:String) {
super(inType, inSender);
buttonName = inName;
}
}
In the sending class, send the event like this:
dispatchEvent(new ButtonEvent(ButtonEvent.ON_BUTTON_PRESSED, this, _name));
It is recommended to type constructor parameters of derived event classes as accurately as possible, to avoid abuse of these events by other classes.
Receiving events
The preferred method for connecting a listener to a sender, is by letting the listener add itself to the sender.
Example of a simple notification:
import org.asapframework.events.EventDelegate;
import org.asapframework.events.Event;
private function createSender () : Void {
var loader:MyXMLLoader = new MyXMLLoader();
loader.addEventListener(MyXMLLoader.ON_ALLXML_LOADED, EventDelegate.create(this, handleAllXMLLoaded));
loader.loadXML();
}
public function handleAllXMLLoaded (e:Event) : Void {
// e.target == loader
// e.type == "onAllXMLLoaded"
}
An example with a derived event:
import org.asapframework.events.EventDelegate;
function listenToButton () {
var button:MySendingMovieclip = new MySendingMovieclip(timeline.button_mc);
button.addEventListener(ButtonEvent.ON_BUTTON_PRESSED, EventDelegate.create(this, handleClick));
}
function handleClick (e:ButtonEvent) : Void {
// e.target == button
// e.type == "onButtonPressed"
// e.buttonName = sender._name
}
Note the use of EventDelegate, the framework version of the Macromedia Delegate class. Use of this class has two advantages:
- the existence of the handler method can be checked at compile time
- the name of the handler can be different from the name of the event
Data management
Most applications require some form of data to be loaded and exposed to various areas of the application. In order to provide a single access point for all available data, a DataManager can be created according to the Singleton pattern. This ensures that only one instance is available at any time, and that it is available in all parts of the code.
The following code sets up the skeleton for the DataManager class:
import org.asapframework.events.Dispatcher;
class DataManager extends Dispatcher {
private static var theInstance:DataManager = null;
private function DataManager () {
}
public static function getInstance () : DataManager {
if (theInstance == null) {
theInstance = new DataManager();
}
return theInstance;
}
}