20
Nov
07

Dispatching Custom Events

In Chapter 3, we cover the basics of using events. One topic that's not covered extensively (appearing in later chapters), is using the dispatchEvent() method to send a specific, or even custom, event. This method is contained within the EventDispatcher class.

The dispatchEvent() method takes an Event object as its first and only argument. The following code will dispatch a custom event of type "my event":

dispatchEvent(new Event("my event"));

You can also use any AS3 event constant:

dispatchEvent(new Event(Event.INIT));

The below class dispatches an event after a one second timer has elapsed:

package {

    import flash.utils.Timer;
    import flash.events.TimerEvent;
    import flash.events.EventDispatcher;
    import flash.events.Event;

    public class DispatchEventExample extends EventDispatcher {

        private var _timer:Timer;

        public function DispatchEventExample() {
            _timer = new Timer(1000, 1);
            _timer.addEventListener(TimerEvent.TIMER, onTimer,
                                    false, 0, true);
            _timer.start();
        }

        private function onTimer(evt:TimerEvent):void {
            dispatchEvent(new Event("one second elapsed"));
        }
    }
}

To listen for the event, use the addEventListener() method. Similar to when dispatching events, as discussed previously, you can either listen for an event constant (such as Event.ENTER_FRAME, or your own custom event class), or a simple string. Here is an example document class that listens for the "one second elapsed" event:

package {

    import flash.display.Sprite;
    import flash.events.Event;

    public class Main extends Sprite {

        private var _dispatchExample:DispatchEventExample;

        public function Main() {
            _dispatchExample = new DispatchEventExample();
            _dispatchExample.addEventListener("one second elapsed",
                                      onOneSecond, false, 0, true);
        }

        private function onOneSecond(evt:Event):void {
            trace("_dispatchExample has dispatched an event");
        }
    }
}


 

A Note About EventDispatcher and DisplayObjectContainer

It's important to note that display object containers subclass the EventDispatcher class:

Object -> EventDispatcher -> DisplayObject -> InteractiveObject -> DisplayObjectContainer

This means that any sprite, movie clip etc., has the ability to use dispatchEvent().

 

Applied Example

We've added a class to our set of packages called OpenSlider. It's a robust, easily skinnable slider class. See it in action below:

This movie requires Flash Player 9. Please update your player.

Download: OpenSlider  Download OpenSlider (35.1 KB, 1,634 hits)

The OpenSlider class only needs the instance names of two display objects on the stage. The rest is done behind the scenes:

var scribbleSlider:OpenSlider = new OpenSlider(scribbleBtn,
                                               scribbleLine);

OpenSlider dispatches a CHANGE event when the slider is dragged to a new position. To listen for this event you would write something along the lines of:

scribbleSlider.addEventListener(Event.CHANGE, onSliderChange,
                                false, 0, true);

Once the event is received you can access the percent getter for the slider to read it's new value:

function onSliderChange(evt:Event):void {
    trace(evt.target.percent);
}

Alternatively, if you want values in a range other than 0-1 you can use the setRange() method and then get or set value property:

// set range
scribbleSlider.setRange(-5, 5);

// read value
trace(scribbleSlider.value);

What's important about OpenSlider in the context of this post is that it uses dispatchEvent() internally. Without getting too deeply into the class as a whole, here is a bit of code that shows where the dispatchEvent() method is used:

private function onBtnDown(evt:MouseEvent):void {
	_btn.stage.addEventListener(MouseEvent.MOUSE_UP,onBtnUpOutside);
	_btn.startDrag(false,_rect);
	_btn.addEventListener(Event.ENTER_FRAME,onChange);
	_btn.stage.addEventListener(Event.MOUSE_LEAVE,onBtnUp);
}
private function onBtnUp(evt:MouseEvent):void {
	_btn.stopDrag();

	_btn.removeEventListener(Event.ENTER_FRAME,onChange);
	_btn.stage.removeEventListener(Event.MOUSE_LEAVE,onBtnUp);
	_btn.stage.removeEventListener(MouseEvent.MOUSE_UP,onBtnUpOutside);
}
private function onBtnUpOutside(evt:MouseEvent):void {
	if (evt.target!=this) {
		_btn.stopDrag();
		_btn.removeEventListener(Event.ENTER_FRAME,onChange);
	}
	_btn.stage.removeEventListener(Event.MOUSE_LEAVE,onBtnUp);
	_btn.stage.removeEventListener(MouseEvent.MOUSE_UP,onBtnUpOutside);
}
private function onChange(evt:Event):void {
	if (_scrollMode == "horizontal") {
		_percent = (int(_btn.x)-int(_rect.left))/int(_rect.width);
	} else {
		_percent = (int(_rect.bottom)-int(_btn.y))/int(_rect.height);
	}
	dispatchEvent(new Event(Event.CHANGE));
}

To summarize the above, while the _btn display object is being dragged, an ENTER_FRAME is run that recalculates the _percent variable and continuously dispatches a CHANGE event. The ENTER_FRAME event is removed when the _btn display object stops being dragged. To see the rest of the source code for the class, download the demo, above.

The new event model is one of the biggest differences between AS3 and previous versions of ActionScript. Check the related post about dispatching built-in events in specific circumstances, and check back for more posts on this topic.

Print This Post Print This Post

Related Content



9 Responses to “Dispatching Custom Events”


  1. 1 What about adding a property for an event Nov 7th, 2008 at 12:16 am

    What if you want to add data to the event being dispatched. So that your listener could grab some data from the event much like the COMPLETE event for an external XML Call. Is that possible.

    Jim

  2. 2 Rich Nov 7th, 2008 at 3:02 am

    Jim, this isn't possible in the given mechanism that AS3 uses for events. However, you can create a custom Event class that will allow this for specific uses. I'll write a post this weekend to show a simple example. It should be up by some time Monday afternoon.

  3. 3 Esteban Mar 6th, 2009 at 2:03 am

    Nice and clear example. The OpenSlider class is extremely useful. Thanx for sharing.
    I will go on and read your other posts.
    Cheers!

  4. 4 Alex Jeffery Jul 29th, 2009 at 7:42 am

    Thanks for this tutorial. I had been looking for a clear example of custom events so I could implement a reusable toolbar widget for a Flash game.

  5. 5 Felix Oct 22nd, 2009 at 9:59 pm

    Hey Rich nice book.

    can you tell me what this line does?

    dispatchEvent(new Event(Event.CHANGE));

    I see people always put this line in the end, does this code tell flash to update the event?

    Thanks

  6. 6 Rich Oct 22nd, 2009 at 10:28 pm

    @Felix, that line actually dispatches the event, just like pressing the mouse button dispatches an event like MOUSE_DOWN.

    The first part of the process is to create a new event, using new Event(). Within that structure, you include the event constant for the type of event you want to dispatch (in the example you cited, it was Event.CHANGE). Alternately, you can simply dispatch a string (which is what the event constants contain). The second part is to dispatch that newly created event with dispatchEvent().

    If you include a second argument (optional) true within the event creation step, the event will bubble up through the display list: dispatchEvent(new Event(Event.CHANGE, true));.

    Thanks to Zevan for writing this post!

  7. 7 Felix Oct 25th, 2009 at 7:27 am

    Hey Rich, thanks for the explaining.
    I just made my own customEvent and it works fine!

  8. 8 jimfo Feb 24th, 2010 at 9:35 pm

    Is it possible to pass an object array or other data types other than strings in the event object? I have been trying to pass an array along with the event object. The eventData variable is an array. So when I try to do this then I get an implicit coercion error can't convert array to string. I know that I can pass a string back split it up into an array using the split method of the String Class. Is there a way to pass native data types such as an array in the event object.

    public override function clone():Event {
    return new CustomEvent(type, eventData, bubbles, cancelable);
    }

  9. 9 Rich Feb 24th, 2010 at 9:46 pm

    @Jimfo, yes, you can pass any data type with an event. Check out the "Creating a Custom Event Class" section of the Passing Arguments with Events post.

Leave a Reply




Speaking

Archives