Event Handlers versus Event Listeners

Flash ActionScript 2.0

A number of ActionScript classes feature something called events.  An event is raised by an object when a certain occurrence happens.  For example, when someone hovers over a button symbol in a SWF, the Button.onRollOver event is raised for that particular Button instance.  When the mouse is moved elsewhere, the Button.onRollOut event is raised for that same instance.  These events take place whether or not anyone takes notice.  If you want to actually do something in response to an event, you must manage it with an event handler or an event listener.  The choice between these two is determined by the object — some objects expect handlers, some listeners — so hit the ol’ ActionScript Language Reference when in doubt.  Handlers are relatively easy, but for some reason, listeners seem to perplex people at first.  Let’s take a look at both. 

Event Handlers

The most popular events probably belong to the Button and MovieClip classes, which happen to share many of the same (a movie clip can be a button, but not the other way around).  To handle the Button.onRelease event, all you have to do is drag a button symbol to the Stage and give it an instance name via the Properties inspector.  Use this name in a frame script to assign a function to the event.

myButton.onRelease = function() {
  // do something
}

The other Button events work the same way, as do the MovieClip events and all events that require event handlers.

Any number of events can be handled.  Just assign a function to each event, as necessary.  A button that responds to a roll over, release, and roll out, for example, might look like this …

myButton.onRollOver = function() {
  // do something
}
myButton.onRelease = function() {
  // do something
}
myButton.onRollOut = function() {
  // do something
}

Event Listeners

Managing event listeners requires a few more steps.  A listener is accomplished with a generic Object instance.  This object acts as a liaison between at least two others:  the object that raises the event, and any objects listening for the event.  Let’s look at a MovieClipLoader example.

var mcl:MovieClipLoader = new MovieClipLoader();

At this point, we’ve declared a variable, mcl, that points to an instance of MovieClipLoader.  Now we’ll declare another variable, mclListener, that points to an instance of Object.  (Sounds funny, I know, but we’re creating an Object object.)

var mclListener:Object = new Object();

This generic object will now become our liaison.  At this point, the code looks very similar to the event handler approach.

mclListener.onLoadInit = function() {
  // do something
}

I could have picked any event from the MovieClipLoader class, it really doesn’t matter.  The thing to notice here is that a generic object is handling the event on behalf of the operative class instance.  With event handlers, the operative class instance handles its own events.

Now that we have our listener, and now that a function has been assigned to one of its events on behalf of our MovieClipLoader instance, we simply need to subscribe the listener to mcl.

mcl.addListener(mclListener);

Done.  Let’s see that all in one take:

var mcl:MovieClipLoader = new MovieClipLoader();
var mclListener:Object = new Object();
mclListener.onLoadInit = function() {
  // do something
}
mcl.addListener(mclListener);

To listen for more than one event, just follow suit with the event handler approach.

var mcl:MovieClipLoader = new MovieClipLoader();
var mclListener:Object = new Object();
mclListener.onLoadStart = function() {
  // do something
}
mclListener.onLoadProgress = function() {
  // do something
}
mclListener.onLoadInit = function() {
  // do something
}
mcl.addListener(mclListener);

27 Responses to “Event Handlers versus Event Listeners”

  1. Caroosoh Says:

    It would be great if you could talk a little about HOW to use Listeners, Broadcasters etc. inside AS 2 classes!

  2. David Stiller Says:

    Caroosoh,

    Event handlers, listeners, and broadcasters are used the same way in AS2 classes as they are in FLA timelines. Would you give me an example of what you’d like to see? I’ll be happy to explain.

  3. Caroosoh Says:

    OK (and thanks for the chance). :-)

    I imagine a clip MultiLoader class that extends MovieClipLoader:
    the constructor accepts one parameter, that’s an Array of JPG paths.

    How to control the onLoadComplete (and other events, onLoadInit etc.) for every single JPG? How to insert it in the class?

    If you open the gallery_tween.fla (mx 2004) example you’ve it all in a keyframe: I don’t understand how to use it in a class, how to make it work, how to design the class.

  4. David Stiller Says:

    Caroosoh,

    I’ll tell you what. Your question is a good one. :) I’ve added your topic to my list. This merits a full tutorial, rather than just a comments reply, so I will write something on multiple loads … keep your eyes peeled.

  5. Caroosoh Says:

    I’m waiting for the good tutorial, then :-)

  6. Lopez Says:

    Argh, I’m so close…

    Thanks to your tutorial above, I finally understand how everything is working with each other in regards to listeners and MovieClipLoader instances, but I’m after the tutorial that Caroosoh mentioned…many months ago…?

    Where the listener and MovieClipLoader are inside a custom written class?
    The way they are written above would only seem to work in AS1 not AS2.

  7. David Stiller Says:

    Lopez,

    The code in this blog entry is ActionScript 2.0, so you could certainly use it in an AS2 class file. I’m glad you mentioned the article I promised Caroosoh, because … heh, I still owe that one. It’s on my list, but I keep bumping it, because I simply haven’t yet made time. Thanks for the reminder! But certainly, if you want to experiment on your own, you could use the principles described above.

  8. Tiemen Says:

    I’m not sure, but I think I remember your name from the macromedia newsgroups. A lot of good people there.

    The reason I stumbled here is because I’m also trying to write a custom class that uses the MovieClipLoader. To be honest, I don’t understand the classes principle fully, but I think my problem is that I want the class to create a container movieclip AND utilize that container to load a clip into using the MovieClipLoader. But I can’t let it extend two classes…

    Structure looks like this (don’t mind the schematic syntax):

    class Classname extends MovieClip {
    function Constructor (){
    createEmptyMovieClip(Container)
    loadClip(Container)
    }
    }

  9. David Stiller Says:

    Tiemen,

    You betcha, I’ve been on the Macromedia (now Adobe) boards for a long time.

    To address your comment, it’s important you realize that writing classes does not inherently mean you must extend a base class. You can write a class that uses any number of existing classes — this is called “composition,” and it happens even if you simply use an array in your class — and that’s perfectly valid.

    For something like what you describe, it makes sense to declare at least two properties: a) a MovieClip property to store some movie clip reference (the target to be used by MovieClipLoader) and b) a MovieClipLoader property to hold your MovieClipLoader instance.

    In many regards, a custom class is nothing more than standard keyframe code. It’s probably more organized, but in the end, it’s “just plain ActionScript.”

    class Classname {
      // properties
      private var mc:MovieClip;
      private var mcl:MovieClipLoader;
      // constructor
      public function Classname(url:String, target:MovieClip):Void {
        mc = target;
        mcl = new MovieClipLoader();
        mcl.loadClip(url, mc);
        // etc.
      }
    }

    Notice that the constructor is named the same as the class (not the word “constructor”).

    What comes next is up to you, of course. :) I don’t know in what way you mean to use MovieClipLoader here. I imagine you might want to have a common occurrence transpire when the loaded asset is fully downloaded; if so, MCL’s onLoadInit event will provide that information — but if that’s all this class is expected to do, I would just use MovieClipLoader. In the context of a larger class (or series of classes), something like this might make perfect sense … you might be writing a Slideshow class, and this could possible be a Slide class that handles its own loading. In that case, your Slide class may hold additional information, such as photographer, time the photo was made, perhaps a sound to play, etc.

  10. Tiemen Says:

    Wow first off I’d like to really comment on your entire blog. Initially I stumbled on your site by means of Google and placed the comment above, but after that I went to explore the rest of the blog and it is stunningly great! Much better then all the tutorial sites I have come through and the tone of your blog entries is truly very sympathetic and intelligent at the same time. The ideal combination (for me) to learn and accept from. And the joyful updates about Meridian (original name) are pleasant too when your head is spinning with code..

    Regarding the above. I knew it would come down to writing lines of code, but as these are comments, I didn’t want to fully write out what I have going on, but this ’schematic’ way doesn’t quite cut it either, so let me explain. Of course my contructor function has the same name as my class.

    What I want the class to do is to load external jpegs, using the movieClipLoader from a path passed as parameter. Secondly I’d like to manipulate the depth in which the container movieclip is created, so images can be placed behind or in front of certain objects.
    And lastly I want to be able to manipulate the actions incurred when various event handlers of the movieClipLoader are invoked. Like you mentioned above.

    I put it in one class, one function, but though the parameters are passed, the movieClipLoader doesn’t instantiate, leading me to believe what I posted in the previous post.

    My code looks as follows;

    class preLoader extends Movieclip {
    //I had to extend it in order to use the createEmptyMovieClip, later on.

    private var FILE = file_param
    private var DEPTH = depth_param

    public function actionLoad() = load_function
    public function actionProgress() = load_progress
    public function actionComplete() = load_complete
    public function actionInit() = load_init
    public function actionError() = load_error

    function preLoader (file_param, depth_param) {

    var loader_mcl = new movieClipLoader();
    var listener_obj = new Object();

    listener_obj.[loading handlers] {actionFunction}
    //all the loading events, plus corresponding functions, see start of class

    this.createEmptyMovieClip (”container_mc”, DEPTH)
    loader_mcl.addListener(listener_obj)
    loadClip(FILE, container_mc)
    }
    }

    For once: movieClipLoader is not instantiated. Not initialized. Does nothing. And I know the part concerning the loading action functions is erroneous, don’t know yet how I can get that to work correctly.

  11. David Stiller Says:

    Tiemen,

    Wow first off I’d like to really comment on your entire blog.

    Hey, thanks for the kind words! :-D Your reaction is exactly the reason I hang out on the forums and write articles for this blog. That made my afternoon.

    What I want the class to do is to load external jpegs, using the movieClipLoader from a path passed as parameter.

    Sounds good. We’ll take this step by step, to match your three goals. So far, if this was your only goal, I would personally just use the MovieClipLoader class. The same instance can be used repeatedly to load any number of JPGs into any number of movie clip containers.

    var mcl:MovieClipLoader = new MovieClipLoader()
    mcl.loadClip("one.jpg", clipA);
    mcl.loadClip("two.jpg", clipB);
    mcl.loadClip("three.jpg", clipC);

    In the above example, the MovieClipLoader events wouldn’t be of much use, because you can only track the downloading of one JPG at a time [Note! This is incorrect, as clarified in a later reply to Tiemen], but you could certainly load images in sequence this way, firing off a new loadClip() method as needed.

    Secondly I’d like to manipulate the depth in which the container movieclip is created, so images can be placed behind or in front of certain objects.

    First, a few thoughts about depth. Once the SWF is published — that is, once timeline layers are no longer part of the equation — depth occurs on a movie clip basis. Movie clips placed or created with ActionScript always appear on top of movie clips placed by hand in a timeline. In ActionScript 2.0, it is not possible to specifically move the child of one movie clip in front of the child of another: the movie clips themselves would have to be swapped, and all the children of both would move with them.

    Now, if all of that is okay (and it has to be, unless you’re using AS3), then at this point, I would still — perhaps — not necessarily write a custom class to do the swapping. (I might, but then somewhere along the line, some class would have to keep track of all the images.)

    And lastly I want to be able to manipulate the actions incurred when various event handlers of the movieClipLoader are invoked.

    For this, it would probably make sense to instantiate one MovieClipLoader instance for each loaded image, so that each separate image could have its loading tracked. At this point, it might indeed be time to write a custom class, if only to have one place to manage all these instances. This could very quickly become complex, if you wanted to keep track of each instance’s events separately.

    I put it in one class, one function, but though the parameters are passed, the movieClipLoader doesn’t instantiate, leading me to believe what I posted in the previous post.

    Aha. Okay. Looking at your code …

    var loader_mcl = new movieClipLoader();

    … I see that you’ve scoped your MovieClipLoader instance to the constructor function itself. This variable, because it is declared inside this function, only “lives” as long as the function is active. In effect, as soon as your custom class is instantiated, your MovieClipLoader instance is deleted. Declare this variable as a private property at the top — outside any function — and initialize it, if you like, in the constructor or some other method.

    //I had to extend it [MovieClip] in order to use the createEmptyMovieClip, later on.

    Well, yes and no. True, you need a MovieClip reference in order to use the createEmptyMovieClip method, but it would make your class just as portable (re-usable) if that MovieClip reference were, say, passed into the constructor. As a general rule, inheritance (extending a class) should only occur when the subclass (the new class) is an instance of the base class. Your preLoader class doesn’t seem to need an onEnterFrame event; it doesn’t seem to need _x, _y, _width, _height, or other position/scale properties normally associated with a movie clip. The MovieClip class defines dozens of properties, methods, and events, but — so far — it looks like you only need one of those (createEmptyMovieClip()), so I would caution against extending such a complex class unless you really need to. The overhead simply isn’t necessary.

    Does that make sense?

  12. Tiemen Says:

    Thanks David, for the extended reply. By the way, what are the tags you use to style your blogs/comments?

    Regarding the issue again.
    I figured that if I used the movieClipLoader class to load several clips into several containers using the same listener - this topic - they indeed would interfere. First off some basics… for me to understand the instancing of classes and event handlers, because actually, I don’t understand fully what happens. First I create an object instance and assign it to be an instance of the movieClipLoader class, and then I create an object which is defined using the event handlers onProgress etc. later to be used as listener, which will come into action only when you link this object to the movieClipLoader object using [movieClipLoader_instance].addListener([object_which_has_event_handlers_assigned_to_it])?

    So if I want to be able to use different loading event handlers for different loading events I have to create new instances of the movieClipLoader because only one loading listener can be attached to each movieClipLoader instance? (Checking if I understood correctly.)

    About depth; I knew indeed that all negative depth is reserved for objects on stage, that actionScript created objects can only have positive depths. But still I want to manager those depths in which I create the containers, later to be the images. This way I can use for instance one loader for the background images and one for content images on the pages. To load the images behind stage objects I have to use the swapDepths method, or simply create a background image container mc on the stage. Right?

    [quote]Well, yes and no. True, you need a MovieClip reference in order to use the createEmptyMovieClip method, but it would make your class just as portable (re-usable) if that MovieClip reference were, say, passed into the constructor.[/quote]

    Hmm this I don’t follow. When I initially created the class I didn’t extended anything, bucked the movieClipLoader part including the container-creation into the constructor, and got the “There is no method with the name ‘createEmptyMovieClip’.” error. How does that referencing work? And why doesn’t it give the same error about the loadClip method? Naturally it felt wrong to let this class be an extension of the movieClip class, because of the same reason you described, but I didn’t got it to work otherwise.

    Well, I go on recreating the class using your tips, reporting back soon!

  13. Tiemen Says:


    class preLoader extends MovieClipLoader

    private var FILE:String
    private var DEPTH:Number

    public var actionProgress:Function

    private var loader_mc:MovieClipLoader = new MovieClipLoader();
    private var listener_obj:Object = new Object();
    private var container_mc:MovieClip = this.createEmptyMovieClip("container_mc", DEPTH);

    //constructor

    public function preLoader (FILE_param, DEPTH_param) {

    this.FILE = FILE_param;
    this.DEPTH = DEPTH_param;

    }

    public function movieLoad(FILE, DEPTH) {

    listener_obj.onLoadProgress = function(targetMC) {}

    loader_mc.addListener(listener_obj);
    loader_mc.loadClip(FILE, container_mc)

    }
    }

    Does not work (yet): Errors reported:

    **Error** C:\Documents and Settings\Ghita Bouman\Desktop\Nieuwe Site\as\preLoader.as: Line 12: A class's instance variables may only be initialized to compile-time constant expressions.
    private var loader_mc:MovieClipLoader = new MovieClipLoader();

    **Error** C:\Documents and Settings\Ghita Bouman\Desktop\Nieuwe Site\as\preLoader.as: Line 14: There is no method with the name 'createEmptyMovieClip'.
    private var container_mc:MovieClip = this.createEmptyMovieClip("container_mc", DEPTH)

    Not extending the MovieClipLoader class returns the same errors.

  14. Tiemen Says:

    eh.. my attempt to style it has removed some syntax, but the syntax is correct in the original, I promise :)

  15. David Stiller Says:

    Tiemen,

    We’re veering somewhat from the focus of the original blog entry, so I’d like to aim specifically more toward event handling/listening in this particular entry than toward class writing. That said, this is a good conversation, and thanks to your questions, I’ve researched the MovieClipLoader class in greater detail — and have learned where I was mistaken in a few areas, so I’ll leave it in place. :) Here are my replies (and thanks!).

    By the way, what are the tags you use to style your blogs/comments?

    Mainly <code>, occasionally <blockquote>, and mainly just typing. :)

    First off some basics… for me to understand the instancing of classes and event handlers, because actually, I don’t understand fully what happens.

    Each instance of a class — any class — represents a single object that has available to it all the properties, methods, and events defined by that class. In the case of MovieClipLoader, you may invoke the loadClip() method as often as you like on a given MovieClipLoader instance. If you load 50 images, you may even handle all 50 sets of events from that single instance — this is where I was incorrect earlier — though who knows how complex that might get. (In truth, it wouldn’t actually be 50 sets of events, but the same 6 events of any MovieClipLoader instance … just … well, firing rather often, on behalf of each image.)

    So if I want to be able to use different loading event handlers for different loading events I have to create new instances of the movieClipLoader because only one loading listener can be attached to each movieClipLoader instance? (Checking if I understood correctly.)

    If you have a single MovieClipLoader instance, you may re-assign any number of functions to its MovieClipLoader.onLoadInit event, for example — but only one of those functions would be active at a given time. If you loaded images sequentially, that wouldn’t matter. If you used a single MovieClipLoader instance and loaded 50 images simultaneously, the same function (the same event handler) would occur for each.

    In this sample code …

    this.createEmptyMovieClip("clipA", 0);
    this.createEmptyMovieClip("clipB", 1);
    clipB._x = 400;
    
    var mcl:MovieClipLoader = new MovieClipLoader();
    mcl.loadClip("A.jpg", clipA);
    mcl.loadClip("B.jpg", clipB);
    
    var listener:Object = new Object();
    listener.onLoadInit = function():Void {
    	trace("Image loaded!");
    }
    mcl.addListener(listener);

    … you’ll see the “Image loaded!” message appear twice in the Output panel, but you’ll have no idea (except maybe visually) to determine which image loaded first, and consequently which image triggered the function first. [Note! This is embarrassingly incorrect. Every one of the MovieClipLoader events carries with it a way to identify the target clip to which it is associated. I’m putting in this note in hopes I don’t steer anyone astray, but I’m leaving in the original wording because, hey, I make mistakes like anyone else, and a little humble pie is good for the soul.] This may suit you fine, or it may make sense for you to instantiate one MovieClipLoader object for each image.

    On the other hand, the MovieClipLoader.onLoadProgress event lets you know which movie clip it’s loading into.

    In this sample, very similar …

    this.createEmptyMovieClip("clipA", 0);
    this.createEmptyMovieClip("clipB", 1);
    clipB._x = 400;
    
    var mcl:MovieClipLoader = new MovieClipLoader();
    mcl.loadClip("A.jpg", clipA);
    mcl.loadClip("B.jpg", clipB);
    
    var listener:Object = new Object();
    listener.onLoadProgress = function(mc:MovieClip, bytes:Number):Void {
    	trace(mc + ": " + bytes);
    }
    mcl.addListener(listener);

    … the mc parameter indicates which container clip contains the bytes number of bytes.

    To load the images behind stage objects I have to use the swapDepths method, or simply create a background image container mc on the stage. Right?

    MovieClip.swapDepths() will do it.

    When I initially created the class I didn’t extended anything, bucked the movieClipLoader part including the container-creation into the constructor, and got the “There is no method with the name ‘createEmptyMovieClip’.” error. How does that referencing work?

    If there is not MovieClip instance to reference, then indeed, there is no createEmptyMovieClip() method on which to invoke the method. Functions are free-range and can be called anywhere; methods require an object instance; specifically an object instance that was instantiated from the class that supports the desired method.

    Currently, your class accepts two parameters:

    function preLoader (file_param, depth_param)

    … so make it accept three paramters, one of which is a movie clip reference.

    function preLoader (container, file_param, depth_param)

    As long as container is a MovieClip instance, you can use container.createEmptyMovieClip() in your class code.

    Incidentally, I strongly recommend you use post colon suffixes in your code. For example …

    function preLoader (
      container:MovieClip,
      file_param:String,
      depth_param:Number
    )

    … because that keeps you more mindful of the datatypes you’re using. In addition, classes are, by convention, set in title caps, so preLoader would more traditionally be called PreLoader.

    Here is a rough skeleton of how I might approach the class you’re working on. Remember, I don’t know what your full purpose is, or what detail you want to add, but in case “an image is worth a thousand words,” maybe this will do better than my wordiness.

    Note that your movieLoad method accepts a new movie clip container reference with each call, in addition to a “name” parameter, which you could use as your instance name for a newly created clip. I see value in storing a single MovieClipLoader instance and a single Object instance for handling events — but I haven’t suggested how or where to handle these events, but don’t see in my mind’s eye what you’re after.

    I hope showing you this sort of stab-in-the-dark example isn’t a “dangerous” thing. I don’t mean to confuse matters at all.

    class PreLoader {
      // Properties
      private var _mcl:MovieClipLoader;
      private var _listener:Object;
      // Constructor
      public function PreLoader() {
        _mcl = new MovieClipLoader();
        _listener = new Object();
      }
      // Methods
      public function movieLoad(
        mc:MovieClip,
        name:String,
        file:String,
        depth:Number
      ) {
        mc.createEmptyMovieClip(
          name,
          mc.getNextHighestDepth()
        );
        _mcl.loadClip(file, mc[name]);
      }
    }
  16. Tiemen Says:

    Holy **** David, that’s a whopping reply!

    I’m going to bed now, so I’ll keep it short..

    In the case of MovieClipLoader, you may invoke the loadClip() method as often as you like on a given MovieClipLoader instance. If you load 50 images, you may even handle all 50 sets of events from that single instance — this is where I was incorrect earlier — though who knows how complex that might get.

    You meant this part?

    or this, it would probably make sense to instantiate one MovieClipLoader instance for each loaded image, so that each separate image could have its loading tracked. At this point, it might indeed be time to write a custom class, if only to have one place to manage all these instances. This could very quickly become complex, if you wanted to keep track of each instance’s events separately.

    From what I’ve learned firing a bunch of loadClips on a single MovieClipLoader instance returns for each image separate event results, so indeed there we have no problems there, but that wasn’t exactly my issue.

    I wanted the action taken on the 6 (5? onLoadStart, onLoadProgress, onLoadComplete, onLoadInit and onLoadError?) events to be manipulable from the outside, while the creation of a container clip and the loading itself remains hidden in the class.

    Your example code looks very elegant as in the container-creation part & subsequent loading into it. Managing the depth of the container still has my preference, as this will allow multiple container mc’s on one “mc”, and still remain in control of their superposition (in contrast with the getNextHighestDepth()), for instance

    movieLoad(background_mc, "layer 0", "ground.jpg", 0)
    movieLoad(background_mc, "layer 1", "trees.jpg", 1)
    movieLoad(background_mc, "layer 2", "clouds.jpg", 2)

    This way I won’t have to bother which movie loads first, which would be a problem using getNextHighestDepth. Oh well.. not yet the moment for finetuning :/

    … you’ll see the “Image loaded!” message appear twice in the Output panel, but you’ll have no idea (except maybe visually) to determine which image loaded first, and consequently which image triggered the function first. This may suit you fine, or it may make sense for you to instantiate one MovieClipLoader object for each image.

    I’m not sure it this sequencing thing bothers me. I think I’ll work that out using the action I’m planning to use in the event handler functions.
    My big question of tonight: How do I control those functions from the outside/ how do I paste entire functions between those handlers inside the class?

    Oh and though it looks great, and worked out even greater, your rough sketch doesn’t work (here). All the MovieClip objects come out fine, all parameters come through fine, but the MovieClipLoader still won’t fire up.

    Still a bit crucial in this whole custom MovieClipLoader class story ;-)

    I’m amazed at your devoted feedback David, and I’m really sorry about letting blog entry become more and more a forum topic… that’s normally not what commenting is about :-/ But it sure is pretty frustrating not getting this simple class to work.
    The event handlers themselves are after reading this a peace of cake though. :P

  17. David Stiller Says:

    Tiemen,

    No worries. :) I have one or two more comments, but then we’ll round out this conversation — at least, for the time being. I’m about to write a blog entry on the topic of using MovieClipLoader in a class (many people have shown interest, and I promised ages ago I’d put it “on my list,” so it’s time to deliver).

    Managing the depth of the container still has my preference, as this will allow multiple container mc’s on one “mc”, and still remain in control of their superposition (in contrast with the getNextHighestDepth())

    That’s the nice thing about programming: the preference is yours, as a programmer. :)

    This way I won’t have to bother which movie loads first, which would be a problem using getNextHighestDepth.

    Not sure what you mean by that. If you were incrementing depths yourself, it would amount to the same thing, really.

    My big question of tonight: How do I control those functions from the outside/ how do I paste entire functions between those handlers inside the class?

    Functions may be passed around just like objects (they are objects), so from an outside-control point of view, it’s not especially difficult. How to manage an number of such connections, that’s the part that has my scratching my head, because some events carry with them a reference to the loaded object (onLoadProgress), while others (onLoadInit) do not — at least, not that I can see.

    There are only five events, by the way. Thanks for noticing that!

  18. Travis Says:

    This was a great tutorial, thanks for clearing a few things up.

    Alas, like others, I am still running into problems.

    I am very new to Flash and Actionscript but have gotten a few things to work.

    I have a main movie clip which loads several *.ai images, basically a map with different sets of icons. In one of the layers there are a couple hundred icon text pairs. I am trying to attach a listener to each one programmatically so that I can do some work when they are clicked; grab the text and change the icon color.

    I have an actions frame with code that adds zoom and preview buttons as well a context menu. I am trying to add the listeners in the same section of code. I can add a click listener event to the movie clip itself and that seems to work. but when i try to loop through the properties of the movie clip and add a listener I am unable to catch the event.

    I am not adding this code to on() or onClipEvent().

    Code:

    var stationListener:Object = new Object();
    stationListener.onPress = function()
    {
    trace( "Station press..." );
    };
    stationListener.click = function()
    {
    trace( "Station click..." );
    };
    stationListener.mouseDown = function()
    {
    trace( "Station mouseDown..." );
    };
    for( var key:String in map.stations )
    {
    var obj = eval( map.stations[key] )
    obj.addListener( stationListener );
    trace( "" );
    trace( "Key:" + key );
    trace( "Value:" + obj );
    trace( "Type:" + typeof( obj ) );
    };

    Outputs:
    Key:instance1
    Value:_level0.layers.stations.instance1
    Type:object

    From Debug List Object:

    Movie Clip: Frame=1 Target="_level0.layers.stations"
    Shape:
    Edit Text: Target="_level0.layers.stations.instance1" Variable= Visible=true Text = STN1\r"

    From Debug list variables:

    Movie Clip: Target="_level0.layers.stations"
    Edit Text: Target="_level0.layers.stations.instance1"
    htmlText = "STN1\r",
    tabIndex = undefined, textHeight = 8,
    text = "STN1\r",
    filters = [object #27, class 'Array'] [], bottomScroll = 1, password = false, embedFonts = false,
    hscroll = 0, maxscroll = 2, length = 5, textColor = 0,
    multiline = true, html = false, scroll = 1, variable = null,
    gridFitType = "pixel",
    restrict = null, border = false, selectable = false, background = false,
    backgroundColor = 16777215, condenseWhite = false, maxhscroll = 0, styleSheet = undefined,
    type = "dynamic",
    antiAliasType = "normal",
    autoSize = "none",
    mouseWheelEnabled = true, textWidth = 13, wordWrap = false, maxChars = null,
    thickness = 0, borderColor = 0, sharpness = 0

    I was hoping that I did not have to go through and convert all of the icons to symbols.

    Any thoughts, comments or help is greatly appreciated.

  19. David Stiller Says:

    Travis,

    You nailed it, actually — those icons do need to be symbols. It’s the symbol wrapper that makes all the difference, because until your imported image is a movie clip, that artwork is not an instance of the MovieClip class. The class definition of the object at hand is fundamentally responsible for what that that object can do.

    In your code, for example, what is obj? Clearly, it refers to whatever map.stations[key] is — but (and here’s the important part) what datatype is map.stations[key]? Does that datatype support an addListener() method?

    In the original article, the mcl.addListener(mclListener); line works because mcl is an instance of the MovieClipLoader class, and that class features an addListener() method.

  20. Travis Says:

    Wow, thanks for the quick reply.

    I was afraid that is what the answer would be.

    So I guess the question is should I do this programmatically or manually? I had gotten atleast a portion of this work by converting a couple of the pairs to movieclips. However, to do this I had to “break apart” all of the grouping within flash which caused my zoom to stop working.

    In a language I am actually familliar with, I would create my own nested movieclip sublass that holds an instance of the icon( shape ) and the text portion each as its own movieclip, so that I can control the changes individually and still tie the event handling to the overall symbol. However, manually creating these symbols doesnt seem to work this way.

    I do not expect you to give me all the answers here, I am just not really sure what to start looking for in the documentation or tutorials.

    Would I be better off trying to do this in Flex?

    Thanks again for your help.

  21. David Stiller Says:

    Travis,

    Flex operates in ActionScript 3.0 land, which requires a whole new map. The principles are the same — you would still need to convert those raw images into whatever class instance meets your needs — but you’d have to change gears quite a bit. Flex Builder 2 has no timeline or drawing tools. It’s a different IDE that caters to a different sort of developer.

    That said, Flex Builder 2 is arguably “just another” ActionScript editor, same as Flash. I put that in quotes because both applications are immensely complex, and Flex Builder 2 is an awesome code editor — but the point is that ActionScript is what matters. The tool used to write it isn’t nearly as important as what the language requires or is capable of. (Honestly, you can produce SWFs without any Adobe software at all [see osflash.org].) So even in Flex, you’ll have to mass-convert those images.

    The Flash IDE is programmable via JSFL, and that might be a good solution for you. See the “Extending Flash” book in the documentation. If you’re comfortable with JavaScript, you’ll find you can program the IDE by way of a DOM what works, in principle, to the DOM in HTML.

  22. Swan Says:

    One thing, that, i was searching explanation for is :
    Why there are two types of “binders” ie.

    1) AddEventListener
    2) AddListener.

    The 2nd one can be understood, but the 1st one always confuses, as why there is the necessity of mentioning the type of event which is going to be bound with the object. As in the following case :

    mylistener.click = function () { // do something }
    mybutton.addEventListener ( “click”, mylistener )

  23. David Stiller Says:

    Swan,

    I can’t answer authoritatively why addEventListener() needs the seemingly redundant information, but for what it’s worth, that method is the preferred approach in ActionScript 3.0. With very few exceptions, addEventListener() is the new way to handle events. The other approaches, including addListener() are a result of new functionality added to Flash over the years. So the reason there are two “binders,” at least in ActionScript 2.0, may well be that various teams worked on various implementations of the API over various years.

  24. Swan Says:

    Thanks,
    Btw, the good thing i like about quip, is that you ALWAYS respond, with a reply. :)

  25. David Stiller Says:

    Swan,

    Thanks! I really do try to always respond. Sometimes it takes me a very long time.

  26. automator Says:

    Hi, David! Thanks for this informative article. I’m currently in the process of understanding the difference between event handlers and event listeners and your article has helped a lot (although I’m still a bit confused, but considerably less confused than I was before reading your explanation :) ). Would you be so kind as to clarify something for me? When you say “an event is raised by an object”, is it the same as saying “an object broadcasts an event”. For example, when you press a button (let’s say it has the name myBtn), the myBtn button instance “raises the onPress event”, and if an onPress event handler method is assigned to myBtn, then the onPress event handler method is invoked and then something happens (plays a sound, for example). Would this explanation be somewhat correct as well:

    When myBtn is pressed, it “broadcasts”: “hey, I’ve just been pressed!”. And then the event handler method (which is assigned to the myBtn button) is activated and then something happens.

    Would that be a correct explanation? Because the way I understand it is that with event handlers, the object that “broadcasts” the event is also the one listening out for when that specific event is broadcast (so the object is kinda like talking to itself). Where as with event listeners, one object broadcasts the event and then another different object (the listener object) listens out for those events that are broadcast.

  27. David Stiller Says:

    automator,

    When you say “an event is raised by an object”, is it the same as saying “an object broadcasts an event”.

    I would say yes. In day-to-day discussions, I generally hear the concept in question described as “an event being raised,” “an event being triggered,” and “an event being broadcast.” All of these refer to an event occurring, and then it’s up to your event handler function to “handle” the event.

    The part where it gets hazy — and this may be 100% in the way I (mis)represented the concept — is that even listeners can be said to handle events. That makes the phrase “event handlers vs. event listeners” potentially confusing.

    What I’m calling “event handlers” in this article are essentially nothing more than properties, if you look carefully at it (and maybe I should have been more careful! ;) ). The Button.onRelease “property” is assigned to a function, which makes it actually do something when its namesake event occurs.

    What I’m calling “event handlers” have a one-to-one correspondence between the event and the triggered function. What I’m calling “event listeners” can have a one-to-many correspondence. You might, for example, have 100 different listeners all listening for a particular event to be broadcast. It’s in that scenario that the term “broadcast” seems (to me) like a good fit. But out of laziness, perhaps, I often use the word “broadcast” for all of the above.

    I hope that clears the somewhat muddy water!

Leave a Reply