overview
learn how to implement events for a class
start by building a general event system
then apply the system to an example
java's delegation event model
event broadcasting system in java is called "delegation event model"
we'll apply that system to actionscript
participants
three participants in the event delegation model:
general structure
event occurs (e.g., mouse click, ending of a game, new user joins a chat...etc)
event source broadcasts event by invoking an agreed-upon method on all event listeners
event object is passed to agreed-upon method as an argument
event listeners respond as they see fit (e.g., submit a form, show a game over screen, display a welcome message to the new chat user)
the event source
the event source includes two classes:
EventListenerList: utility to manage event listenersEventListenerList implemenatation
EventListenerList resides in "event" pacakge
class event.EventListenerList { }
EventListenerList also imports the contents of the event package
import event.*;
array of listener objects stored in instance property, listeners
private var listeners:Array;
constructor creates empty listeners array:
public function EventListenerList () { listeners = new Array(); }
addObj() method adds a listener to the listeners array
public function addObj (l:EventListener):Boolean { // Search for the specified listener. var len:Number = listeners.length; for (var i = len; --i >= 0; ) { if (listeners[i] == l) { return false; } } // The new listener is not already in the list, so add it. listeners.push(l); return true; }
removeObj() method removes a listener from the listeners array
public function removeObj (l:EventListener):Boolean { // Search for the specified listener. var len:Number = listeners.length; for (var i:Number = len; --i >= 0; ) { if (listeners[i] == l) { // We found the listener, so remove it. listeners.splice(i, 1); // Quit looking. return true; } } return false; }
getListeners() method returns a copy of the listener list, used to broadcast an event
public function getListeners ():Array { // Return a copy of the list, not the list itself. return listeners.slice(0); }
the event object
the event object includes two classes:
EventObject, a base class for all event objectsEventObject subclass, whose properties and methods describe a specific eventthe subclass is user-defined, per event implementation
EventObject implementation
EventObject resides in "event" pacakge
class event.EventObject { }
EventObject stores a reference to the event source in a property, source:
private var source:Object;
EventObject is passed event source reference at construction time
public function EventObject (src:Object) { source = src; }
getSource() method returns the event source
public function getSource ():Object { return source; }
event source reference used by event listeners to:
subclasses of EventObject will add methods to retrieve event-specific information
the event listener
event listener includes three participants:
EventListener interfacethe EventListener is a "marker interface":
EventListener implementation
source code for EventListener interface
interface event.EventListener { }
events are listed in a subinterface
for example, suppose OrderForm broadcasts two events: onSubmit() and onReset()
corresponding methods are defined in an interface, as follows:
import event.EventListener; interface OrderFormListener extends EventListener { public function onSubmit (e:OrderFormEvent):Void; public function onReset (e:OrderFormEvent):Void; }
then, a class that wants to register for OrderForm events must implement OrderFormListener:
class OrderGUI implements OrderFormListener { public function onSubmit (e:OrderFormEvent):Void { // Code to display submission status on screen goes here... } public function onReset (e:OrderFormEvent):Void { // Code to clear form contents goes here... } }
NightSky: an example
now let's use D.E.M. in an example
a night sky with animated shooting stars
shooting stars appear randomly
participants:
util.Randomizer: event source. triggers an event when it's time to display a shooting starutil.RandomizerListener: interface listing Randomizer eventsutil.RandomizerEvent: contains the time since the last shooting starNightSky: listens for Randomizer events, implements RandomizerListenerNightSky architecture

RandomizerListener implementation
RandomizerListener defines a single method, onRandomAction():
import event.*; import util.*; interface util.RandomizerListener extends EventListener { public function onRandomAction (e:RandomizerEvent):Void; }
parameter, e, must be a RandomizerEvent object
guarantees that the event object will be used correctly
NightSky implements RandomizerListener
RandomizerEvent implementation
RandomizerEvent transfers information from event source (Randomizer) to event listeners (NightSky)
specifically, RandomizerEvent.getTimeSinceLast() tells NightSky when the last shooting star occurred
class util.RandomizerEvent extends EventObject { // The number of milliseconds since the last event was broadcast. private var timeSinceLast:Number; public function RandomizerEvent (src:Randomizer, timeSinceLast:Number) { // Always pass event source to superclass constructor! super(src); // Record the time since the last event, as specified // by Randomizer. this.timeSinceLast = timeSinceLast; } public function getTimeSinceLast ():Number { return timeSinceLast; } }
Randomizer implementation
Randomizer uses setInterval() to check for random events
because event broadcasting is our focus, we'll ignore the code that is not directly related to event broadcasting
Randomizer stores an EventListenerList instance in a property, listenerList:
private var listenerList:EventListenerList;
the EventListenerList instance is created in Randomizer's constructor
listenerList = new EventListenerList();
to register to receive events, a class invokes addRandomizerListener():
public function addRandomizerListener (l:RandomizerListener):Boolean { return listenerList.addObj(l); }
to stop receiving events, a class invokes removeRandomizerListener():
public function removeRandomizerListener (l:RandomizerListener):Boolean { return listenerList.removeObj(l); }
notice that only RandomizerListeners can register for Randomizer events!
because all event listeners must implement RandomizerListener, all are guaranteed to define onRandomAction()
to broadcast the "random action" event, Randomizer uses fireOnRandomAction():
private function fireOnRandomAction (elapsed:Number):Void { // Create an object to describe the event. var e:RandomizerEvent = new RandomizerEvent(this, elapsed); // Get a list of the current event listeners. var listeners:Array = listenerList.getListeners(); // Broadcast the event to all listeners. for (var i:Number = 0; i < listeners.length; i++) { listeners[i].onRandomAction(e); } }
check() determines whether a random event has occurred; if so, broadcasts the event
private function check (odds:Number):Void { // Local variables. var rand:Number = Math.floor(Math.random() * odds); var now:Date = new Date(); var elapsed:Number; // If the random event occurs... if (rand == 0) { // Determine the elapsed time since the last event. elapsed = now.getTime() - lastEventTime.getTime(); lastEventTime = now; // Fire the event. fireOnRandomAction(elapsed); } }
NightSky implementation
NightSky class listens for Randomizer class's events
hence, NightSky must implement RandomizerListener interface
class nightsky.NightSky implements RandomizerListener { }
NightSky creates sky background and shooting stars by attaching movie clips
NightSky defines the following properties:
target: the movie clip that will hold the sky backgroundprivate var target:MovieClip;
sky_mc: a reference to the sky background movie clipprivate var sky_mc:MovieClip;
skyDepth: the depth at which to attach the sky clipprivate var skyDepth:Number = 0;
startDepth: the depth, in sky_mc, to create shooting starsprivate var starDepth:Number = 0;
NightSky constructor receives sky's parent and sky/star depth as parameters
public function NightSky (target:MovieClip, skyDepth:Number, starDepth:Number) { this.target = target; this.skyDepth = skyDepth; this.starDepth = starDepth;
constructor also calls makeSkyBG():
makeSkyBG(); }
makeSkyBG() simply attaches the sky background clip
private function makeSkyBG ():Void { sky_mc = target.attachMovie("skybg", "skybg", skyDepth); }
when an event occurs, onRandomAction() executes
onRandomAction() calls makeShootingStar(), which causes a star to appear on screen:
public function onRandomAction (e:RandomizerEvent):Void { trace("New shooting star! Time since last star: " + e.getTimeSinceLast()); makeShootingStar(); }
the time since the last shooting star is retrieved via e.getTimeSinceLast()
makeShootingStar() source code:
private function makeShootingStar ():Void { // Create the shooting star in the sky movie clip. sky_mc.attachMovie("shootingstar", "shootingstar" + starDepth, starDepth); // Randomly position the shooting star. sky_mc["shootingstar" + starDepth]._x = Math.floor(Math.random() * target.skybg._width); sky_mc["shootingstar" + starDepth]._y = Math.floor(Math.random() * target.skybg._height); // Put the next shooting star on a higher depth. starDepth++; }
putting it all together
to use NightSky in an application, we first import the necessary packages:
import nightsky.*; import util.*;
next, we create a NightSky instance:
var sky:NightSky = new NightSky(bg_mc, 1, 0);
then we create a Randomizer instance:
var starRandomizer:Randomizer = new Randomizer(1000, 3);
finally, we register the NightSky instance to receive events from the Randomizer instance:
starRandomizer.addRandomizerListener(sky);
summary
the delegation event model provide event handling with complete datatype safety
all participants in the system must follow the type rules, so errors are minimized