ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
Understanding the AS3 Event Flow
http://www.actionscript.org/resources/articles/860/1/Understanding-the-AS3-Event-Flow/Page1.html
Jody Hall
My interest in Flash started mostly because of a Jib-Jab cartoon ("This Land") in 2004. I'm the author of a feature I call "Mazoons," which are a combination of mazes and cartoons. In 2002, I even had a book published, "Super Silly Mazes." I'm not a professional programmer, but making my mazes interactive by programming them with Flash became a hobby/obsession of mine, to the point where I have now learned more than I bargained for. Lately I'm working on a new website about Flash and Actionscript 3.0 called The Flash Connection
By Jody Hall
Published on May 25, 2009
 
This article will help you to understand the event flow in Actionscript 3.0, once and for all. It is intended for anyone who is just beginning Actionscript 3.0, and wants to understand the new event model.

Introduction

The switch from Actionscript 2.0 to Actionscript 3.0 saw many changes, as we all know. Some were superficial or minor, like removing underscores from certain properties. So _alpha became alpha. The range of alpha became 0 to 1 (formerly 0 to 100). These are among the small changes. Other changes were more extensive; some much more. Of all the changes, the two biggest ones were undoubtedly the display list and the event model. In fact, if you can master these two aspects of Actionscript 3.0, the remainder should be relatively easy.

Of those two, the display list is the easiest to learn. So that leaves the event model. The new event model relies on a system of event dispatchers and event listeners. The event dispatchers are the various objects in your flash movie. If you create things that can be displayed on the screen, you are creating event dispatchers, because in Actionscript 3.0 all display objects ultimately descend from the EventDispatcher class. So our old familiar friend from Actionscript 2.0, the MovieClip, is now an event dispatcher in Actionscript 3.0! So are all of the other display objects. And many objects that aren't display objects are event dispatchers, too, but those won't be the focus of this article. What we are concerned with here is what is known as the event flow. When a display list is involved, and an event is dispatched by an object on the display list, that event is sent through the display list from object to object, looking for event listeners that have been defined along the way. In this article, you are going to see just how useful that feature can be!

A listener is a function that you write to handle events that are being dispatched. A listener is registered with an event dispatcher using the event dispatcher's addEventListener() method. Even if you are quite new to Actionscript 3.0, you probably have already written some event listener functions and added them to MovieClip instances, because you have to if you want to get any kind of interactivity at all. Maybe you've heard of the event flow, and the associated terminology, and wondered what it was all about, especially in terms of how to make it work for you in your projects, but you were put off because it sounded way too complicated. So you just continue on, adding an event listener to each and every object for each and every kind of event you want to listen for, racking up a huge stack of event listeners, while at the same time having this nagging thought that there must be a better way, something powerful that you're not tapping into and taking advantage of.

That something is the event flow, naturally. Trouble is, it can be very intimidating and confusing at first, as you may have already found out (in the end though, it's not all that bad--and that's the good news)! So, if you've read books, seen diagrams, and consulted the documentation--and still don't understand exactly how it works, let alone what it can do for you, don't worry. I'm betting that you're not alone--and that's why I wrote this article.





The Display List and Event Flow

event_flow_starter_file.fla

To discuss the Event Flow through a display list, we first need a display list. Download the starter fla file linked above, as it contains a very simple display list with a menu and a couple of MovieClip buttons. We are going to be considering here only those events that flow through a display list, and of those, only the events that have a bubbling phase (don't worry if that word is unfamiliar to you; we'll get to explaining the phases later). In fact, we're going to get even more specific than that and only consider one event, the MouseEvent.CLICK event. My feeling is that the best way to get a clear picture of the event flow is to focus on one type of event for now. The CLICK event makes a nice example to look at, and the other events are similar.

Here is what the starter fla file looks like when you run it:


And here is the code that puts the various objects out there on the display list:
[as]var menu = new Menu();
menu.x = 84;
menu.y = 89;
addChild(menu);

var button1 = new ButtonOne();
button1.x = 117;
button1.y = 71;
menu.addChild(button1);

var button2 = new ButtonTwo();
button2.x = 117;
button2.y = 131;
menu.addChild(button2);[/as]
The line addChild(menu) adds the menu to the display list. The menu is being added to the main timeline (root), and not to the stage. You may not have even known there was a distinction. Notice we didn't say stage.addChild(menu). What's the difference? Well, when you create a new fla file, before you even add anything of your own, you automatically get a stage instance to which the root has already been added. It's as though a line of code something like this:
[as]stage.addChild(root);[/as]
...has already been executed for you. The stage and the root provide a foundation on which to build all the rest of your display list. When you add things to the root with addChild or this.addChild (those are equivalent), they automatically get displayed, because the root has already been added to the stage previously. Here is a diagram illustrating the structure of our display list once the above lines of code have executed:

If you have ever added a child to an object's display list, and it didn't show up on the screen when you ran the file, chances are the object you were adding it to didn't have a connection to the stage. It might be helpful to think of the stage object as being analagous to a main electrical power source. You might have a maze of electrical cords that are all plugged into each other, but if they aren't also connected to the main power source at the other end, you don't have power. Similarly, you must ultimately have a connection to the stage for your display object to be displayed.

Now that we have a simple display list, let's discuss it a bit. How do events "flow" through this display list anyway? The answer is that when you add a display object to a display object container using addChild(), the container gets a reference to its new child, and the child gets a reference to its new parent. This creates a chain of objects, each one knowing its parent and each one (if it's a container) having a list of its children. The event flow travels along this chain beginning at the stage. The event object is passed along from object to object thanks to this chain of references.

The following event flow demo swf is intended to show you how this event flow takes place. Try clicking on the various objects in the display list--the buttons, the menu, and even the stage--and watch the event object travel along the event flow. Note how many places it "visits" when you click on the different things:

The Event Flow Demo Swf:

Note: Don't just pass this by! You should click on this demo several times. I know this is a simple display list hierarchy, but I want you to get a good mental picture of the way events flow through it. I will refer back to this demo swf several more times during the course of this article.


There are a lot of things to note here: First, it's important to realize that this event flow takes place whether there are any listeners defined or not (as noted in the demo). Secondly, unlike what you see in this demo, the "real" event object travels through the display list at a much more blinding speed. Thirdly, it should be noted that there are different kinds of event objects, and they carry along with them a lot of valuable information. This event object for a mouse click would be an instance of the MouseEvent class (but for simplicity's sake in the demo I've just labelled it "event object."), and it would carry along infomation specific to mouse events. Later we'll see how to make practical use of this information.

Finally, notice that if you click on either of the buttons, the event object "visits" five places. If you click on the menu, it visits three. If you click on the stage, it only visits one. At each place, it checks to see if there are any event listeners defined there, and if so, their code would be executed.

So, here's what I want you take away from this demo: A mental picture of the event object flowing through a display list and "visiting" the various "places" along the way.  On the next page, we'll examine how to define listeners for each of those "places." Make sure that you've downloaded the starter fla file from the top of this page, if you want to follow along.



Adding Listeners
For now, let's confine our discussion to a single hypothetical mouse click on button1. As you saw in the demo on the previous page, this causes the event object to visit five different places along the event flow. At each place, it looks for any event listeners defined there. Now we're going to consider how we could add a listener to each of those five places. I keep saying "places," and, while that might not be completely correct in a technical sense, I find it helpful to picture them that way, just like in the animated demo on the previous page. But they are really objects, and the stage and menu objects are actually visited twice each, once on the way "in" and once on the way "out." The button1 object is visited once, and that makes a total of five visits altogether, all in a single mouse click.

The Event Phases

The way "in" is called the capture phase. The way "out" is called the bubbling phase. And when the event object is at the button1 object, this is called the target phase. The button1 object dispatched the event and also received the event, and so it is known as the target of the event. The other objects along the event flow would each in its turn be known as the currentTarget. Remember, we are discussing here strictly a click on button1. If anything else is clicked, the identities of the target and currentTarget objects change accordingly. So, in order to fully understand this, we have to confine our discussion to one event flow for now, which has five places where the event object flows to. button1 is the target and the other objects are all currentTarget(s).

We can add event listeners to each of these five places. The addEventListener method is a method of the EventDispatcher class. In Actionscript 3.0, MovieClips now have the EventDispatcher class in their inheritance chain, meaning that they are event dispatchers. So they can dispatch events, and they can have event listeners added to them. The Stage class is also descended from the EventDispatcher class, so it can also dispatch events and have event listeners added to it. So all I'm saying is that we can add event listeners to our stage, the menu, and our buttons.

The addEventListener method has five parameters. Here's the method's "signature:"

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

The first two parameters are the only ones that are required, so you'll often see listeners being added to objects using this short form:

[as]button1.addEventListener(MouseEvent.CLICK, clickHandler);[/as]

This is saying that we want to listen for the CLICK event, that we want the event to call our handler function named clickHandler when the event happens, and that we don't want to listen for the capture phase. Even though we didn't specify that, that's what we will get because the default value for the third parameter, useCapture, is false, and we didn't supply an argument for it (the fourth and fifth parameters, which allow you to set listener priority and specify weak references, go a bit beyond the purposes of this article, but we will consider the useCapture parameter, because it has a lot to do with adding listeners to the different "places" along the event flow):


This diagram illustrates the phases of the event flow when button1 is clicked. We can add listeners to each of those five places, even add multiple listeners to each place if we want. For a click on button one, there are five choices for adding event listeners:

  1. We can add a listener to the stage for the capture phase
  2. We can add a listener to the menu for the capture phase
  3. We can add a listener to the button1 object for the target and bubbling phases
  4. We can add a listener to the menu for the target and bubbling phases
  5. We can add a listener to the stage for the target and bubbling phases

I want you to notice the choices for stage and menu: either capture phase or target and bubbling phases. The choice depends on the value you give the useCapture parameter. If you set the useCapture parameter to true, you have chosen the capture phase. If you set the useCapture parameter to false (or just accept the default value of false by not specifying), you have chosen target and bubbling. Take note that for events that bubble, there is no such thing as setting a listener for just the target phase or just the bubbling phase, as those two go together.

You may or may not find the capture phase especially useful. You would set an event for the capture phase in cases where you might want to conditionally stop the event flow from reaching its target. But you'll soon find out just how useful the target and bubbling phases can be! Note this well: The whole reason for having a bubbling phase is so that you can add event listeners to a container, and still detect events coming from the container's children (The capture phase is similar; it also lets you add a listener to a container and detect events coming from the children. But as noted, you probably won't use it as much).

So let's turn our attention to the starter fla file you downloaded (from page 1). Open it in Flash if you haven't already. Add this code to the end of the other code in frame 1:

[as]menu.buttonMode = true;
button1.buttonMode = true;
button2.buttonMode = true;[/as]

This is just for appearance's sake--setting buttonMode to true will cause each of these objects to have a hand cursor when you hover it with the mouse. The stage doesn't have a buttonMode, so there's no way to get a hand cursor over it (nor would you really want to).

Let's start by adding a listener to the stage for the capture phase:

[as]stage.addEventListener(MouseEvent.CLICK, clickHandler, true);
function clickHandler(event:MouseEvent):void {
    trace("clicked");
}[/as]
In the following illustration, you can visually see that because a listener was added to the stage for the capture phase, it's as though a little note is made at that place in the event flow: call clickHandler:

Test the file with CTRL-ENTER. When you click on button1, you get the message "clicked" traced to the output panel. Even though you didn't add any listener to button1 at all--in fact the only listener has been added to the stage--it still fires when you click on button1. This is because of the event flow, of course! And now all the drawings, diagrams and the demo should be starting to make sense to you.

Try clicking on the other button (button2). The event fires! Click on the menu. The event fires! I want you to picture the event flow as you click each item (think of the demo swf from the preceding page). Click on the stage. The event does not fire. Why not? Because the event listener was added with useCapture set to true. When we click on the stage, the stage is the target. Since stage is the target and has no higher parent, there is no capture phase in this case. Do you remember from the demo that when you clicked on the stage, the event object only visited one place?

I digressed just a bit by having you try clicking on those other things, just to give you a feel for how it works. Now we'll get back to considering only clicks on button1. Let's add a listener to the menu next, also for the capturing phase:

[as]menu.addEventListener(MouseEvent.CLICK, clickHandler, true);[/as]

You could write separate event handler functions, but you can also just re-use the same one, and that's what we'll do. And here's the visual for that:


Once again, run the file by pressing CTRL-ENTER. This time, when you click on button1, you will get the message "clicked" traced to the output window twice. This is because, as in the above diagram, adding those event listeners caused those objects to take note that when they got a click event, they should call the clickHandler function.

Next, let's add an event listener to button1 for the target and bubbling phases:

[as]button1.addEventListener(MouseEvent.CLICK, clickHandler, false);[/as]

Remember that setting that third parameter to false means "don't use the capture phase, use the target and bubbling phases instead." Also, we could have just left off the third argument, because the default value for useCapture is false. I know I'm repeating myself, I just want to make sure everyone gets that. Since the target and bubbling phases are being specified, a click on the button will fire this listener too. It will fire in the target phase, when the event object is at the button itself:


Once again, run the file and click on button1. You will get the "clicked" message traced to the output window three times. Anyone detecting a pattern here? Let's go ahead and add the other listeners to the stage and the menu for the target and bubbling phases:

[as]menu.addEventListener(MouseEvent.CLICK, clickHandler, false);
stage.addEventListener(MouseEvent.CLICK, clickHandler, false);[/as]

Now our listeners are defined in all five places:


All the code we've added so far should look like this (the lines that add event listeners can appear in any order, and above or below the event handler function, it doesn't matter):

[as]stage.addEventListener(MouseEvent.CLICK, clickHandler, true);
function clickHandler(event:MouseEvent):void {
    trace("clicked");
}
menu.addEventListener(MouseEvent.CLICK, clickHandler, true);
button1.addEventListener(MouseEvent.CLICK, clickHandler, false);
menu.addEventListener(MouseEvent.CLICK, clickHandler, false);
stage.addEventListener(MouseEvent.CLICK, clickHandler, false);[/as]

Test the movie again. Click the button. Not surprisingly, you will get the "clicked" message in the output window five times. When we add an event listener to the menu or the stage and specify the target and bubbling phases, we are in both cases adding the event listener to a container.  So when we specify the target and bubbling phases, we are saying that we want to listen for events that happen to the children, too. I'll say it again: The whole reason for having a bubbling phase is so that you can add event listeners to a container, and still detect events coming from the container's children.

Now imagine a menu like ours with, say, ten buttons instead of two. Imagine how handy it will be to just add one event listener to the container menu, instead of each and every individual button. I can almost hear you asking "But how could you make the individual buttons do different things?" We will explore that question, among other things, on the next page. I know this has been a rather long page with a lot of theory and not that much action, but it was necessary to lay this groundwork and get a firm understanding of the event flow. On the next and following pages, we're going start putting it to some really cool uses!



target and currentTarget
To recap, we now have a display list and an event flow. We've seen how to add event listeners for any point in the event flow that we want. But so far, all our listener did was to trace out the message "clicked." We will now see how we can make use of the event object and the information it carries along with it.

The event parameter

When we write an event handler function (also known as the listener), we have to give it one parameter: a variable to store the event object that gets passed. What we name this variable is totally arbitrary. I like to always use the full word "event," but other people might prefer shorter forms like "evt" or even just "e." You could also call it "foo" if you want. Whatever name makes sense to you. But whatever name you choose, you have to make sure you also use that name in the body of the function too.  So, don't use "evt" in the parameter list but then use "event" in the function body--the names must be the same:

[as]function listener(foo:MouseEvent):void {
    //make sure you use the same name from the parentheses above:
    trace(foo.target);
}[/as]

target and currentTarget

The event object is wonderfully useful, because of the information that it stores. It "knows" what object triggered it, and also what object the listener was originally added to:

  1. The object that triggered the event, that is, the object that the event happened to (in our case, the object that was clicked on with the mouse), is known as the target.
  2. The object that the listener was originally added to with addEventListener is known as the currentTarget.

Remember these two rules, and refer back to them if you ever get confused about target and currentTarget.

I touched briefly on target and currentTarget earlier, on the previous page. These are properties of the event object. When the event object is passed to our handler function, the parameter we provided in the parentheses takes on the value of the event object. So inside the handler function, we can make use of all the properties of the event object, including the target and currentTarget properties. So, to refer to the object that was clicked, we would use event.target, and to refer to the object that the listener was added to, we would use event.currentTarget. Sometimes target and currentTarget refer to the same object. When they do, it's  because the object being acted upon is the same object the listener was added to. Let's give this a real example.

In the starter file, find and delete this block of code that we added earlier:

[as]stage.addEventListener(MouseEvent.CLICK, clickHandler, true);
function clickHandler(event:MouseEvent):void {
    trace("clicked");
}
menu.addEventListener(MouseEvent.CLICK, clickHandler, true);
button1.addEventListener(MouseEvent.CLICK, clickHandler, false);
menu.addEventListener(MouseEvent.CLICK, clickHandler, false);
stage.addEventListener(MouseEvent.CLICK, clickHandler, false);[/as]

We're going to start fresh, and just add one event listener, to the menu. So copy and paste these lines at the end:

[as]menu.addEventListener(MouseEvent.CLICK, clickHandler);
function clickHandler(event:MouseEvent):void {
    trace(event.target);
}[/as]

Notice that there is no third parameter supplied to the addEventListener function, so we are saying that we want to use the target and bubbling phases. (To tell you the truth, the capture phase is worth knowing about, and it has its uses, but you probably won't find it nearly as useful as the target and bubbling phases, which is no doubt why the architects of the event model decided that the useCapture parameter should be set to false by default). When you run this, you will get the listener being called if you click on the menu or any of the menu's children. Whatever you click on is the target. So when you click on the menu, the menu is the target, and your event handler function is notified during the target phase. If you click on one of the buttons, the button you clicked on is the target, and the event handler function is notified in the bubbling phase.

Press CTRL-ENTER to run this, and try clicking on the menu and the buttons. You will get a trace message to the output window that tells you what object is being clicked on. Pretty cool! Let's refine this a bit:

[as]menu.addEventListener(MouseEvent.CLICK, clickHandler);
function clickHandler(event:MouseEvent):void {
    trace(event.target);
    trace(event.currentTarget);
}[/as]

When you run this, whatever you click on is the target, like before. But now we've refined it to also tell us what is the currentTarget. In all cases, the currentTarget will be the menu. Why? Because it was the object that the listener was added to. Remember those two rules I told you about earlier! So the one case where target and currentTarget are the same is when the menu is being clicked on. When you run this, the output window will inform you of the following:

  1. When the menu is clicked on, the target is the menu, the currentTarget is the menu.
  2. When button1 is clicked on, the target is button1, the currentTarget is the menu.
  3. When button2 is clicked on, the target is button2, the currentTarget is the menu.

No matter what child is clicked on, or even if the menu itself is clicked on, the currentTarget is the menu, because that's the object the event listener was added to. When the menu is clicked on, it is both the target and the currentTarget. If it seems like I'm belaboring this point, it's because I want to make sure you fully understand target and currentTarget, as they are the most useful properties of the event object (for events that "bubble," anyway).

Next, replace the clickHandler function with this version instead:

[as]menu.addEventListener(MouseEvent.CLICK, clickHandler);
function clickHandler(event:MouseEvent):void {
    if(event.target == menu) {
        trace("menu clicked");
    }
    if(event.target == button1) {
        trace("button1 clicked");
    }
    if(event.target == button2) {
        trace("button2 clicked");
    }
}[/as]

Try running this. You can see that you now have complete control over handling a click on the menu, or any of its display object children. Now you can detect exactly what object was clicked on, and take whatever appropriate action you want. Naturally, you are going to want to replace those trace commands with something more useful. How about a menu of links, where the buttons take you to other web pages?

[as]menu.addEventListener(MouseEvent.CLICK, clickHandler);
function clickHandler(event:MouseEvent):void {
    if(event.target == menu) {
        trace("menu clicked");
    }
    if(event.target == button1) {
        navigateToURL(new URLRequest("http://www.google.com"), "_blank");
    }
    if(event.target == button2) {
        navigateToURL(new URLRequest("http://www.amazon.com"), "_blank");
    }
}[/as]

Okay, that's quite a bit more useful! You'll just have to use your imagination here as to what you want the buttons to do. Notice that so far, nothing much special happens when you click the menu. Let's fix that. Using our imagination, how about a menu that we can drag around the screen if the menu is being clicked, but take another action if one of the buttons is being clicked? Now that you understand the event flow for a mouse CLICK, here it becomes necessary to make use of another mouse event, too: MOUSE_DOWN. For the menu to start dragging, we will add an event listener for the MOUSE_DOWN event. MOUSE_DOWN represents the first half of a click. Try the following code:

[as]menu.addEventListener(MouseEvent.CLICK, clickHandler);
menu.addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
function clickHandler(event:MouseEvent):void {
    if(event.target == menu) {
        event.target.stopDrag();
    }
    if(event.target == button1) {
        navigateToURL(new URLRequest("http://www.google.com"), "_blank");
    }
    if(event.target == button2) {
        navigateToURL(new URLRequest("http://www.amazon.com"), "_blank");
    }
}
function downHandler(event:MouseEvent):void {
    if(event.target == menu) {
        event.target.startDrag();
    }
}[/as]

Notice that now the actions for a click on the menu have been changed. If the menu was CLICKED, we tell it to stop dragging. But we've also added an event listener to the menu for the MOUSE_DOWN event, with code to make the menu start dragging. But remember that the menu is a display object container. Similar to the CLICK event, the MOUSE_DOWN event will also fire when you MOUSE_DOWN on the container's children. So inside of that event handler function, we need to use an if statement to make sure that it's the menu that's being MOUSE_DOWN-ed on.

We could have alternatively used the following test in the if statement:

[as]function downHandler(event:MouseEvent):void {
    if(event.target == event.currentTarget) {
        event.target.startDrag();
    }
}[/as]

If the event's target and the currentTarget are the same, then the object receiving the MOUSE_DOWN event is the same one that the event listener was added to, so it must be the menu. I just point this out to drive home the concept of target and currentTarget, and what they represent.

The Working Application

Anyway, here's the working application from the above code. You can actually click the buttons and actually drag the menu in this one. It's not just an illustration, it's a working program. So when you click the buttons and go to other web pages, be sure and come back, okay?


Download the finished fla file

When to use currentTarget instead of target

When should you use target and when should you use currentTarget in your event handler functions?

It's safe to just use target when the object you are adding the listener to is a display object but not a display object container. Or, if the object is a display object container, and you are sure that it doesn't contain other display objects. Remember that MovieClips are display object containers. So if you are programming a MovieClip instance by adding an event listener, and that MovieClip contains or might contain any other display objects (children), remember that the event you are adding a listener for will be active for those children, too.  Because of the event flow, of course.

So, for example, suppose I have a MovieClip instance I'm using for a button, with an instance name of button_mc, and it contains other display objects (even a dynamic textfield used as a label will qualify here), I would want to always refer to button_mc inside the handler function using currentTarget instead of target:

[as]button_mc.addEventListener(MouseEvent.CLICK, clickHandler);
function clickHandler(event:MouseEvent):void {
    event.currentTarget.x += 5;
}[/as]

This little bit of code (unrelated to our example fla file, by the way) will cause the button_mc object to move five pixels to the right when it is clicked. Since currentTarget was used instead of target, there is no danger of the code acting on the wrong object. If target were to have been used instead, and a click had been received by anything contained in mc_button, that other object would have moved instead of mc_button itself.

I'm sure that by now you should understand target and currentTarget completely. Hopefully this is also starting to spark some ideas of your own (a drop-down menu, perhaps?). It's certainly easier to add one event listener to a display object container than to add event listeners to every object inside of it, and that's the whole idea of events that "bubble."


Other useful MouseEvent properties

I have referred throughout this article to the event object in a generic sense. But actually, the event object we have been using is an instance of the MouseEvent class. The MouseEvent class is a subclass of the Event class. Two properties of the Event class, target and currentTarget, are inherited by the MouseEvent class. However, the MouseEvent class defines a few properties of its own that apply specifically to Mouse events, and these are quite useful, too.

For example, the properties altKey, ctrlKey, and shiftKey are Boolean properties that can tell you if those keyboard keys are currently being held down when the mouse event occurs. To use them, just remember that they are properties of the MouseEvent object that your handler function receives as a parameter. So you use them the same way you used target and currentTarget. Example:

[as]button_mc.addEventListener(MouseEvent.CLICK, clickHandler);
function clickHandler(event:MouseEvent):void {
    if(event.shiftKey == true) {
        event.currentTarget.x += 5;
    }
}[/as]

In this scenario, button_mc will move five pixels to the right when it is clicked, but only if the Shift key is also being pressed when the click happens.

Also useful are the localX, localY, stageX, and stageY properties. These properties are Number properties that can tell you the screen coordinates of the mouse pointer's location when the click happened. localX and localY give you the mouse coordinates in relation to the target (in the case of our examples so far, whatever was clicked on). stageX and stageY, meanwhile, give you the mouse coordinates in relation to the stage.

Another useful property of the Event class is type. This property is a String value that can tell you what type of event triggered the listener. This might be useful for combining two or more event handler functions into one. For example, let's consider our sample file as we last left it, and let's combine the two event handler functions into one big one:

[as]menu.addEventListener(MouseEvent.CLICK, clickHandler);
menu.addEventListener(MouseEvent.MOUSE_DOWN, clickHandler);
function clickHandler(event:MouseEvent):void {
    if (event.type == MouseEvent.MOUSE_DOWN) {
        if (event.target == menu) {
            event.target.startDrag();
        }
    } else if (event.type == MouseEvent.CLICK) {
        if (event.target == menu) {
            event.target.stopDrag();
        }
        if (event.target == button1) {
            navigateToURL(new URLRequest("http://www.google.com"), "_blank");
        }
        if (event.target == button2) {
            navigateToURL(new URLRequest("http://www.amazon.com"), "_blank");
        }
    }
}[/as]

It's not that this is necessarily any more desirable than the previous version, but it makes a good example of one possible use of the type property. The main thing is that the type property can tell you what kind of event triggered the listener. What you do with that information is up to you.

There are several other properties of the MouseEvent class (some inherited from the Event class) that you can use in the body of your event handler functions. You should consult the Adobe documentation (help files) for the complete list.

Also available are several methods of the MouseEvent class. One particularly useful method is updateAfterEvent, which can cause the screen to be updated when the event happens, when it would normally be updated only at the framerate of the flash movie. You would use methods of the MouseEvent class the same way you use properties. Just use the name of the event parameter, followed by a dot, then the name of the method, followed by the method call operator ():

[as]event.updateAfterEvent();[/as]

Two other methods worth mentioning here, inherited from the Event class, are stopPropagation() and stopImmediatePropagation(). stopPropagation() will prevent the event flow from continuing beyond the current "place" in the event flow (remember the demo from several pages back?) after the listeners there are executed. stopImmediatePropagation() also prevents the event flow from continuing beyond the current "place" in the event flow, but also doesn't allow the listeners there to be executed (I know my use of the term "place" in the event flow is unofficial; Adobe in the documentation calls it a "node").

The main point is that all of these properties and methods of the Event and MouseEvent classes can be used by you in the body of your event handler functions. Once again, see the documentation for a complete list.

While we have been primarily focused on the CLICK event, the event flow through the display list also applies to most of the other mouse events, like MOUSE_DOWN, MOUSE_UP, MOUSE_OVER, MOUSE_OUT, MOUSE_MOVE, DOUBLE_CLICK, and MOUSE_WHEEL. All of these events will propagate to display object children when the event listener is added to a display object container.

The one pair of mouse events that don't have a bubbling phase is ROLL_OVER and ROLL_OUT. This is on purpose, to give you an alternative to MOUSE_OVER and MOUSE_OUT. You would use ROLL_OVER and ROLL_OUT instead when you want to program a display object container for mouse rollovers, but don't want the rollout to be triggered by the children. Rather, you want to detect only when a rollout happens for the whole container.

I'm sure I haven't covered everything to do with the MouseEvent class, and you can check out whatever I've missed on your own. My main purpose with this article has been to help you understand the Actionscript 3.0 event flow. The MouseEvent.CLICK event served a good purpose as an example of one of the events that flows through the display list. By all means, you should explore and experiment with the other events on your own. As always, I hope I've sparked your imagination and insipired you to create your own flash applications. Send me a link to yours, drop me a line, leave me a comment. Thanks!

Happy coding!

Jody Hall

P.S. I have been building a new website which I call The Flash Connnection. Give it a visit!