Thursday, 10 September 2009

Taking a Closer Look at the ActionScript 3.0 Event Framework

What Are You Going to Learn?

Because the AS3 event framework is huge, we'll look at all the different things which compose the event framework. We'll learn about the following:

  • Events
  • Event dispatchers
  • Event listeners
  • Event flow
  • Often used events
  • And some tips & tricks

Step 1: The Event Framework Simplified

I really think you would have a tough time understanding the event framework if we jump straight into the technical jargon, so I'll first describe a real-life situation. The whole situation is a metaphor for the event framework. Okay, so here we go:

I'm an avid reader of Computer Arts and I wait every single day for the new issue. When I receive the issue, I start reading it.

Step 2: Analyzing the Event Framework Metaphor

Okay, we have several things going on:

  • I receive the new issue. This receiving of an issue is an Event.
  • This event is happening somewhere, it happens to me, I'm the EventDispatcher.
  • I'm waiting for the new issue to arrive. I'm an object and I'm waiting for this event to happen. I'm an object which is listening for the event to happen. I'm an object with an event listener added to me. This event listener is listening to a specific event (namely receiving a new issue).
  • When I receive the issue, I start reading it. When the event has happened, I do something, I execute a function. I'm handling the event. The function that I'm doing is called the handler and/or the listener function.

Step 3: Technical Jargon - Event

I've mentioned several things:

  • Event
  • EventDispatcher
  • Event listener
  • handler / listener function

An Event is an object which describes an occurrence, in Step 1 the event is the arrival of a new issue.

Most times you'll see an event that's written in a structure similar to this:

  1. MouseEvent.CLICK

This snippet of code consists of two things:

  • MouseEvent this is the class that contains one or more events. This is always written in CamelCase.
  • CLICK this is the event type. This is always written in UPPERCASE.

The event type is actually a static constant string. It might sound strange, but an Event is nothing other than a string. Try running this snippet.

  1. trace(MouseEvent.MOUSE_MOVE);

You'll get as output mouseMove. We've just traced the constant MOUSE_MOVE, which is inside the MouseEvent class. An event is a string! But this string represents the occurrence of (in this example) the movement of the mouse.

Step 4: Technical Jargon - EventDispatcher

An event always happens somewhere. Where the event happens is where it gets fired (dispatched). The roots of dispatching events is in the class EventDispatcher. Do realize that where the event is dispatched is where it is happening. So if movie clip A dispatches an event, then an event listener (event listeners will be explained in step 5) added to movie clip B wouldn't receive this event.

To make things easy, all the display objects have the built in function dispatchEvent(event:Event), just like many other classes.

  1. var myMC:MovieClip = new MovieClip();
  2. myMC.dispatchEvent(new Event(MouseEvent.CLICK));

But most times you won't dispatch events manually, most times events are dispatched automatically. For example, if I'd click movie clip A, it would automatically dispatch the event MouseEvent.CLICK.

Step 5: Technical Jargon - Event Listener

When a certain event happens, we, as Flash developers, would like to do something to respond to this event. Event listeners are what you need. Event listeners don't have their own class, no they're a bit different. Event listeners are added to an object. Event listeners are objects that "listen" to a certain event. When this event happens, then a function will be called, a handler (function).

Look at the image below, showing the syntax behind the function addEventListener(), which is used to add an event listener:

Actually those aren't all the parameters the addEventListener method accepts, there are still three that I haven't mentioned. You'll almost never use them, especially when you've just started using event listeners. Let's look again at the structure of the addEventListener method.

  1. addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void

So let's discuss the last 3 parameters:

  • useCapture: When this parameter is set to true, we'll listen to the event in the capture phase. By default this parameter is set to false, thus we listen to the event in the target and bubble phase. We'll discuss the event flow in Step 10.
  • priority: Even though it might seem as if all event listeners work simultaneously, they actually don't. Sometimes they might conflict with each other. This is to make sure that a certain event listener has a higher priority than a different event listener.
  • useWeakReference: When this paramater is set to true it will create a weak link between the object and event listener. Well, what does this mean? Normally objects get garbage collected if there are no references to them. When the object is removed where an event listener is added, it will still exist if it's being referenced somewhere else. This happens with strong memory references. With weak memory references the event listener gets removed when the object it's added to gets removed. I personally set this parameter to true (so I use weak memory references).

Removing an event listener is just as easy as adding one.

  1. //this adds an event listener to the stage
  2. stage.addEventListener(MouseEvent.CLICK, clickHandler);
  3. //this removes the event listener added to the stage
  4. stage.removeEventListener(MouseEvent.CLICK, clickHandler);

Step 6: Handler / Listener Function

When the event occurs that an event listener is listening for, it calls a function. This function is called the handler or the listener function. Look at the image below, showing the syntax of the handler:

Notice the argument in the handler, this argument is compulsory. The listener function only has one argument and is not allowed to have more. This event contains information about the event, we'll talk about this in step 9.

Step 7: Adding an Event Listener and Handler

Now we want myMC to respond to the dispatched event, so we'll add an event and afterwards the handler function. Our code will look like so:

  1. //create our myMC movie clip
  2. var myMC:MovieClip = new MovieClip();
  3. //let myMC dispatch the event MouseEvent.CLICK
  4. myMC.dispatchEvent(new Event(MouseEvent.CLICK));
  5. //add an event listener to myMC, that listens to the event MouseEvent.CLICK, and will call clickHandler
  6. myMC.addEventListener(MouseEvent.CLICK, clickHandler);
  7. //define the handler function
  8. function clickHandler (event:Event){
  9. trace("I heard the event MouseEvent.CLICK");
  10. }

Afterwards test your movie (Windows: Ctrl + Enter, Mac: Cmd + Enter).

Did you get any output? No? Well, neither did I. We'll look at what's going wrong in the next step.

Step 8: Code Order

So what's going wrong? Well, it can't be a syntax error, at least I'm not getting anything. No, this is technically not even an error. Look at the code again, but this time remember that the code will be executed line by line:

  1. //create our myMC movie clip
  2. var myMC:MovieClip = new MovieClip();
  3. //let myMC dispatch the event MouseEvent.CLICK
  4. myMC.dispatchEvent(new Event(MouseEvent.CLICK));
  5. //add an event listener to myMC, that listens to the event MouseEvent.CLICK, and will call clickHandler
  6. myMC.addEventListener(MouseEvent.CLICK, clickHandler);
  7. //define the handler function
  8. function clickHandler (event:Event){
  9. trace("I heard the event MouseEvent.CLICK");
  10. }

I hope you've realized what's gone wrong: the event is being dispatched before an event listener has been added to myMC. So when the event listener has been added, it's too late, the event has happened. Luckily it's easy to solve, just change the order and first add the event listener, then afterwards dispatch the event:

  1. //create our myMC movie clip
  2. var myMC:MovieClip = new MovieClip();
  3. //add an event listener to myMC, that listens to the event MouseEvent.CLICK, and will call clickHandler
  4. myMC.addEventListener(MouseEvent.CLICK, clickHandler);
  5. //let myMC dispatch the event MouseEvent.CLICK
  6. myMC.dispatchEvent(new Event(MouseEvent.CLICK));
  7. //define the handler function
  8. function clickHandler (event:Event){
  9. trace("I heard the event MouseEvent.CLICK");
  10. }

So why did we do all that? Well, you'll likely encounter this problem and it might take a while to realize what's going on. It's better to show you the problem and teach you how to solve it.

Step 9: The Event Argument

Every handler function has one argument; the event argument. This argument contains data about the event and the event dispatcher. The parameter contains properties that we would like to read. Here's a list of some of the most commonly used ones:

  • target: This returns the target object and thus the event dispatcher of the event.
  • currentTarget: This returns the currently targeted object within the event flow, we'll talk about the event flow in Step 10.
  • type: This will return the event string. The value is always written in camelCase. So MOUSE_DOWN has the value mouseDown.

With this we can use the same handler for different types of events. How? Well we'll discuss this in the next step.

Step 10: Multiple Events, One Listener Function

Okay, first let's look at this snippet of code:

  1. stage.addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
  2. stage.addEventListener(MouseEvent.MOUSE_UP, upHandler);
  3. function downHandler(event:MouseEvent){
  4. trace("Down");
  5. }
  6. function upHandler(event:MouseEvent){
  7. trace("Up");
  8. }

We're using two events, namely MouseEvent.MOUSE_DOWN and MouseEvent.MOUSE_UP. The first event is the event when the mouse presses the primary mouse button and holds it down. When the person releases this button, then the event MouseEvent.MOUSE_UP happens. The mouse button goes up after releasing it.

Now we can use instead of two handlers (namely downHandler and upHandler) just one handler. Remove the code we've written and type following:

  1. stage.addEventListener(MouseEvent.MOUSE_DOWN, handler);
  2. stage.addEventListener(MouseEvent.MOUSE_UP, handler);
  3. function handler(event:MouseEvent){
  4. trace("Something has occurred...");
  5. }

Okay, we've set up our handler and it works, but we want our handler to do something specific, depending on which event is passed to the handler. Luckily, we can use event.type. Let's use it!

  1. stage.addEventListener(MouseEvent.MOUSE_DOWN, handler);
  2. stage.addEventListener(MouseEvent.MOUSE_UP, handler);
  3. function handler(event:MouseEvent){
  4. if(event.type == "mouseDown"){
  5. trace("Down");
  6. }else{
  7. trace("Up");
  8. }
  9. }

Step 11: Event Flow

Now let's say that a click happens on a movieclip, let's call it mcA. The event doesn't simply get dispatched at mcA, no, the event travels through the whole player. This traveling is called the event flow, just think how the event is flowing through the player.

The event starts at the top level, at the stage, afterwards it will go through the parents of mcA, until the event reaches mcA. Afterwards the event will "bubble" back from mcA, back to the stage.

Ok, cool, but what can I use this for? Because we now know that an event travels through all the parents of the dispatcher, we can use just one event listener, to track the events of more than one object.

Step 12: Multiple Objects, One Event Listener

Okay, so let's create some multiple movie clips inside each other. You can do this yourself, or just use the step-11.fla file provided.

We'll create 3 movie clips and we'll give them the instance names redMC, blueMC and greenMC. Afterwards place all these inside a bigger movieclip, named container.

Now let's start writing code. I've already created a layer named Actions, so write your code on that layer. First let's add an event listener to container, listening to the event MouseEvent.CLICK, with the handler named clickHandler.

  1. container.addEventListener(MouseEvent.CLICK, clickHandler);
  2. function clickHandler(event:MouseEvent){
  3. //function body
  4. }

We want to know which button is being clicked, so why did we add an event listener to container? Well, look at the picture below:

As you see, the event is being dispatched at redMC, however it will bubble back to container. Then the event listener added to container will hear the event and will call the listener function clickHandler. The same happens with blueMC and greenMC.

Now we're going to use event.target, because event.target is the event dispatcher, and the event dispatcher is redMC. So how we can use event.target? We can check for event.target.name, which returns the instance name as a string. So we can just use normal if statements:

  1. container.addEventListener(MouseEvent.CLICK, clickHandler);
  2. function clickHandler(event:MouseEvent){
  3. if(event.target.name == "redMC"){
  4. trace("Red");
  5. }
  6. if(event.target.name == "blueMC"){
  7. trace("Blue");
  8. }
  9. if(event.target.name == "greenMC"){
  10. trace("Green");
  11. }
  12. }

Step 13: Often Used Events

Now you have a good understanding of the event framework, however to achieve something, the key thing is to know which event to use. A great place to check which events exist, is the ActionScript 3.0 Language and Components Reference. Just click an event containing class, like MouseEvent, and look at what each event is.

Step 14: MouseEvent.MOUSE_MOVE

This event occurs when the user moves the mouse. If you add an event listener listening to this event, on, let's say, a movieclip named myMC, then you'd know when the mouse is moving over myMC.

  1. myMC.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
  2. function mouseMoveHandler(event:MouseEvent){
  3. trace("Your mouse is moving over myMC");
  4. }

Step 15: MouseEvent.MOUSE_OVER

This event occurs when the user moves over (hovers). This event only occurs when the user moves the cursor from somewhere else over the object. Moving the mouse over the object is then no longer the event MouseEvent.MOUSE_OVER, but the event MouseEvent.MOUSE_MOVE.

  1. myMC.addEventListener(MouseEvent.MOUSE_OVER, overHandler);
  2. function overHandler(event:MouseEvent){
  3. trace("You just moved the mouse on myMC");
  4. }

Step 16: MouseEvent.MOUSE_OUT

This event is precisely the opposite of MouseEvent.MOUSE_OVER. This is when the user's cursor moves off the object, or as they (the guys that created AS3) call it, out of the object.

  1. myMC.addEventListener(MouseEvent.MOUSE_OUT, outHandler);
  2. function outHandler(event:MouseEvent){
  3. trace("You just moved the mouse out myMC");
  4. }

Step 17: MouseEvent.MOUSE_DOWN

This event occurs when the user presses the primary mouse down, while it's being held down.

  1. myMC.addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
  2. function downHandler(event:MouseEvent){
  3. trace("The primary mouse button is pressed down on myMC");
  4. }

Step 18: MouseEvent.MOUSE_UP

This event is precisely the opposite of MouseEvent.MOUSE_DOWN. When the user releases the primary mouse button, then the event MouseEvent.MOUSE_UP occurs.

  1. myMC.addEventListener(MouseEvent.MOUSE_UP, upHandler);
  2. function upHandler(event:MouseEvent){
  3. trace("The primary mouse button has been released, while it was hovering over myMC");
  4. }

Step 19: MouseEvent.CLICK

Well the name already makes it pretty clear when this event occurs. This event occurs when the user clicks (with the primary mouse button).

  1. myMC.addEventListener(MouseEvent.CLICK, clickHandler);
  2. function clickHandler(event:MouseEvent){
  3. trace("You just clicked myMC");
  4. }

Step 20: MouseEvent.DOUBLE_CLICK

Well this event occurs when the user clicks twice (with the primary mouse button). Do note that when MouseEvent.DOUBLE_CLICK occurs, that MouseEvent.CLICK is occurring for the second time.

  1. myMC.addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler);
  2. function doubleClickHandler(event:MouseEvent){
  3. trace("You just double clicked myMC");
  4. }

If you now test your movie and double-click, nothing will happen. Why? Well by default movie clips (and almost all display objects) have the property doubleClickEnabled set to false. So MouseEvent.DOUBLE_CLICK won't be dispatched. Just set it to true, and everything will work fine.

  1. myMC.addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler);
  2. function doubleClickHandler(event:MouseEvent){
  3. trace("You just double clicked myMC");
  4. }
  5. myMC.doubleClickEnabled = true;

Step 21: Event.ENTER_FRAME

This event occurs every time the object enters a new frame (yes, that sounds a bit weird). Well basically this event occurs at the rate of the frame rate. That means that if your movie has a framerate of 30 fps, then the event will be called 30 times a second. What would you use this event for? You can use this event to make things happen gradually. For example you could increase an object's x coordinate by 5, at the rate of the frame rate.

  1. myMC.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
  2. function enterFrameHandler(event:Event){
  3. myMC.x += 5;
  4. }

Step 22: Event.COMPLETE

This event occurs when the object completes whatever it was doing. Most times you'll use it for things that need to load something, or for things that play some form of media. An URLLoader loads an URLRequest, after the URLLoader completes loading, then we'll load this data into a different loader and afterwards add the loader to the stage.

  1. var myURLRequest:URLRequest = new URLRequest("http://farm3.static.flickr.com/2382/1616598266_bafebf0086_o.jpg");
  2. var myURLLoader:URLLoader = new URLLoader(myURLRequest);
  3. myURLLoader.dataFormat = URLLoaderDataFormat.BINARY;
  4. myURLLoader.addEventListener(Event.COMPLETE, completeHandler);
  5. function completeHandler(event:Event){
  6. var loader:Loader = new Loader();
  7. loader.loadBytes(myURLLoader.data);
  8. addChild(loader);
  9. }

Step 23: Event.RESIZE

This event occurs when the flash player or the page where the flash is contained is resized. You can use this event to reposition objects after the resizing has happened.

  1. stage.addEventListener(Event.RESIZE, resizeHandler);
  2. function resizeHandler(event:Event) {
  3. trace("The dimensions of the stage are "+stage.stageWidth+" x "+stage.stageHeight);
  4. }

Step 24: KeyboardEvent.KEY_DOWN

This event occurs when any key is pressed on the key board.

  1. stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
  2. function keyDownHandler(event:KeyboardEvent){
  3. trace("You just pressed a key!");
  4. }

Step 25: KeyboardEvent.KEY_UP

This event is precisely the opposite of KeyboardEvent.KEY_DOWN, this event occurs when any key is released (the key goes up).

  1. stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
  2. function keyUpHandler(event:KeyboardEvent){
  3. trace("You just released a key");
  4. }

Step 26: Using the built in key booleans

Of course, it's pretty useless to respond to any key (except for a screen saver), so we would need to retrieve information as to which key has been pressed. Luckily, some of the keys are built into the class KeyboardEvent, these are booleans and are set to true when it's being pressed down. These built in booleans are:

  • KeyboardEvent.altKey, this is set to true when the alt key is pressed down.
  • KeyboardEvent.commandKey, this is set to true when the command key is pressed down (AIR only).
  • KeyboardEvent.controlKey, this is set to true when the control (ctrl) key is pressed down (AIR only).
  • KeyboardEvent.ctrlKey, this is set to true when the control (ctrl) key is pressed down on Windows. However on Mac ctrl key is true when the cmd key is pressed.
  • KeyboardEvent.shiftKey, this is set to true when the shift key is pressed down.

So now we can use this to be more specific which key must be pressed before we do something.

  1. stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
  2. function keyDownHandler(event:KeyboardEvent){
  3. if(event.shiftKey){
  4. trace("You just pressed the shift key");
  5. }
  6. }

Step 27: Using Key Codes

You might be wondering, okay, what about all the other keys? Well there's something called the key code. Every key has a certain number; a key code. We can check the key code of the key that triggered the event. This is done with event.keyCode, which returns an integer. Click here for a list of key codes. Even though it's for javascript, the key codes are the same.

  1. stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
  2. function keyDownHandler(event:KeyboardEvent){
  3. if(event.keyCode == 65){
  4. trace("You just pressed the A key");
  5. }
  6. }

Now it's easier to store the key codes in a variable (or if you're hardcore, in a class) and just use that variable, instead of the key code.

  1. var A:uint = 65;
  2. stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
  3. function keyDownHandler(event:KeyboardEvent){
  4. if(event.keyCode == A){
  5. trace("You just pressed the A key");
  6. }
  7. }

Step 28: Using Character Codes

With key codes you can get quite a lot done, however it sometimes isn't what you need. For example, the same key is used for the characters a and A. But we'd still want to differentiate between those two. Well, the event carries the character code of the event dispatcher.

  1. stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
  2. function keyDownHandler(event:KeyboardEvent) {
  3. trace(event.charCode);
  4. }

Okay, this works, however do we then need to remember these character codes? No. Luckily we can use the function charCodeAt(), which returns the character code of a character (in a String). charCodeAt() takes by default the first character out of the string. charCodeAt(0) is the first character, charCodeAt(1) the second, etcetera.

  1. stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
  2. function keyDownHandler(event:KeyboardEvent){
  3. if(event.charCode == String("a").charCodeAt()){
  4. trace("You just pressed the lowercase a key");
  5. }
  6. }

Step 29: Focus

Now try typing the following:

  1. myMC.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
  2. function keyDownHandler(event:KeyboardEvent){
  3. trace("You just pressed a key, while being focused on myMC");
  4. }

Try testing this, it won't work! Why? If myMC is a movie clip, it won't accept keyboard input, thus keyboard events won't be dispatched at movie clips. If you want myMC to respond, add the event listener to the stage and then make myMC do something. Try changing myMC from a movie clip to a dynamic text field, then it will work.

What about two dynamic text fields? If the user types, do both text fields dispatch an event? No, only the one you're typing in. This is called focus. Keyboard events are dispatched by the object which has focus. The stage is the only object that still has focus, while a different object also has focus.

Step 30: TimerEvent.TIMER

This event is specially built for timers. It gets dispatched at a timer, that just reached the delay time. This means that you can use this event to do something very precisely, at set time intervals.

  1. var myTimer:Timer = new Timer(1000, 5);
  2. myTimer.start();
  3. myTimer.addEventListener(TimerEvent.TIMER, timerHandler);
  4. function timerHandler(event:TimerEvent){
  5. trace("one second later...");
  6. }

Step 31:TimerEvent.TIMER_COMPLETE

All timers have an optional second parameter. This parameter is sets the repeat count of the timer. This means that when the timer reaches the delay time, it will start again. If the timer has repeated as often as the repeat count, it will dispatch the event TimerEvent.TIMER_COMPLETE.

  1. var myTimer:Timer = new Timer(1000, 5);
  2. myTimer.start();
  3. myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timerHandler);
  4. function timerHandler(event:TimerEvent){
  5. trace("The timer has repeated 5 times");
  6. }

Conclusion

That was it! I hope that you now have a thorough understanding of ActionScript 3.0's event framework. Do realize that the events discussed aren't all the events that exist, I just discussed the ones I use often. Don't forget to always check the language and components reference, it can help you a lot! It was a pleasure writing for you guys!

source from : flash tuts+

0 nhận xét:

Post a Comment

 

Blogroll

Site Info

Text

Tut - Designer Copyright © 2009 WoodMag is Designed by Ipietoon for Free Blogger Template