Museum Pieces: on() and onClipEvent()
ActionScript has evolved by leaps and bounds in the last few years. The commercial release of Flex 2.0, and the public release of Flash Professional 9 ActionScript 3.0 Preview, in particular, nudge ActionScript 3.0 that much closer to the world in which we Flashers live. The less-than-adventurous (nothing wrong with that!) won’t see AS3 until the commercial release of Flash 9 — still a long way off, as of this writing. But when that does happen, our world will change. That really isn’t an exaggeration. There will be those who code in AS1/AS2 — there will still be plenty of room for that — and those who code in the jaw-droppingly more complex AS3. The Flash 9 Player, already upon us, now features two virtual machines: one that displays Flash 8 and prior content, and one that displays Flex and Flash 9 content. That’s a first.
And yet, there’s still an awful lot of on() and onClipEvent() going on out there. Is that so terrible? Well, those event handling mechanisms were introduced in Flash 5. In spite of their age, they haven’t been formally deprecated, so they’re perfectly “legal,” strictly speaking. I can even muster a pragmatic smile for anyone who strongly feels that “if it ain’t broke, don’t fix it.” But honestly, dot syntax event handling offers more control than that directly applied to the object. Not only that, but the newer approach lets you organize your code into one place. Let’s take a look.
The old way
The on() handler is primarily aimed at button symbols, but it works with movie clips, too. In Flash 5, it was necessary to attach the following to one of those objects (that is, you would actually click the button to select it, then open the Actions panel and enter code):
on(release) {
// instructions here
}
This configuration specifically handles the release event, which occurs when the mouse is clicked, then released, over the button (or movie clip). Other events include press, releaseOutside, rollOut, rollOver, dragOut, dragOver, and keyPress.
The onClipEvent() handler is geared at movie clip symbols, and only works with movie clips. The code arrangement for this handler is the same:
onClipEvent(enterFrame) {
// instructions here
}
This configuration handles the enterFrame event, which occurs at a rate more or less equivalent to the SWF’s framerate. Other events include load, unload, mouseMove, mouseDown, mouseUp, keyDown, keyUp, and data. Note that mouseUp is not the same as release: release is only fired when the mouse is released while hovering over the object in question; mouseUp is fired if the mouse is released anywhere.
Just remember, you can use on() with movie clips if you like. In effect, move clips handle all the events available to buttons, and then some. But it gets even better.
The “new” way (new since Flash MX)
The dot notation approach appears as if it requires more typing — and truthfully, it does — but not by much. In any case, it’s just as easy to code. In this scenario, the ActionScript goes in a frame script rather than direct attachment. Make sure your button or movie clip has an instance name (select it and look at the Property inspector; you’ll find it), then use that instance name in the following manner:
instanceName.onRelease = function() {
// instructions here
}
In your code, “instanceName” will be replaced with the actual instance name you chose. You’re simply calling the object by name and telling it what to do when a certain event is raised. You may either use a function literal, as shown, or declare a named function and assign that, instead.
instanceName.onRelease = namedFunction;
function namedFunction():Void {
// instructions here
}
Benefits of the new way
Again, why is this better? Let me count the ways.
- 11 button events, versus the previous 8
- 18 movie clip events, versus the previous 9
- Code may be maintained in a single frame, if desired
- Events may be assigned, deleted, and changed programmatically
Okay, okay, four bullet points isn’t a boat load, but it’s certainly enough reason to make the switch, if you haven’t.
Points 1 and 2 speak for themselves. To see all the events available to either object, look up the Button class and MovieClip class entries, respectively, in the ActionScript 2.0 Language Reference.
Point 3, to my thinking, is a significant improvement over the old Flash 5 approach. When you have twenty buttons in front of you, it’s much more convenient to click inside a single frame to see everything you’re after than be obliged to click on each button individually.
Point 4 is perhaps the least obvious, but don’t overlook it! Remember those twenty buttons? What if most of them do essentially the same thing, with the one difference depending only on labeling? What if you have forty buttons? Is there an easier way than to write forty event handlers?
With the new approach, if you like, you can assign similar event handler functions with a for statement. For example, if your buttons send the playhead to respective frame labels, get creative and match your instance names with those labels:
var buttons:Array = new Array("uno", "dos", "tres");
for (var i:Number = 0; i<buttons.length; i++) {
this[buttons[i]].onRelease = function():Void {
_root.gotoAndPlay(this._name);
}
}
In the above, an arbitrarily named variable, buttons, points to an Array instance that contains three strings. A for statement uses another arbitrarily named variable, i, to count from zero to the number of items in the array (thanks to the Array.length property). Inside this loop, a pair of nested array access operators, [], resolves the array’s strings into button instance names; the Button.onRelease handler of each button, in turn, is instructed to send the main timeline to a frame label that shares the same name as the button instance itself. (For further details on this technique, see this article on referencing objects dynamically).
In addition, you can delete event handlers, simply by using the delete statement or by setting the object’s event to null. The following lines are functionally identical.
delete uno.onRelease;
uno.onRelease = null;
Why is this useful? Well, if you’re using the MovieClip.onEnterFrame event to animate a clip …
clip.onEnterFrame = function():Void {
this._x += 5;
}
… you can stop animating it by removing the function. If you want the clip to stop moving when it hits the right site of the Stage, for example …
clip.onEnterFrame = function():Void {
if (this._x >= Stage.width) {
this.onEnterFrame = null;
} else {
this._x += 5;
}
}
With onClipEvent(enterFrame), you’d have to change that += 5 increment to an increment of zero, instead. Yes, the enterFrame function would keep ticking — after all, there’s nothing stopping it — but that’s just how it used to be. It’s unnecessary processing, and enough of that sort of thing can slow a SWF down.
So when you’re digging through FlashKit.com or any other online sample code repository, keep in mind, you don’t have to use what you find 100% as is. Break it apart, use it for inspiration, sure, but by all means, feel free to update it.
June 29th, 2006 at 9:21 pm
Also, knowing what
thisis in aon()handler can be tricky. With the code:on a
MovieClip, it will trace that movieclip, but on aButton, it will trace the parent clip.Similarly, when you don’t use
this,on a
MovieClip, will return the_xof that movieclip, while on aButton, it will trace the_xof the parent clip.So for buttons, how do you make them reference themselves? The only way is to put the instance name within the handler, e.g. for
my_btn:will decrease the
_alphaof the button everytime you press it.In dot-syntax, it makes more sense.
thiswill reference the instance that the event handler belongs to, whether it be aButton, aMovieClip, or aTextField. However, when you drop thethis, it’s a little different. It will look from the timeline on which you have placed the code. For example, say you have the clip,asdf_mc, in which you have placed the following code:and of course,
abc_btnon the_roottimeline, it will output the_xofasdf_mc, not the_root’s and notabc_btn’s (whether it is a button or a movieclip).The nice thing about this is that it is constant with
MovieClips, Buttons, andTextFields, unlike theon()handler.June 29th, 2006 at 9:54 pm
All the more reason to leave
Great points, NSurveyor. Thanks for the input!
on()behind.July 3rd, 2006 at 9:01 am
delete uno.onRelease;
uno.onRelease = null;
Actually, these two produce different results… I’m not sure if it’s a bug or not, but in any case the NULL statement will remove the functionality of the onRelease, but still shows the flash “hand” on rollover.
You have to use the DELETE statement to get rid of the whole shebang.
Granted it took some anal-retentiveness to care enough to find out about this problem and its solution.
July 3rd, 2006 at 9:11 am
Bowser,
Wow, good catch! That’s definitely a point worth making. In my own experience, both
deleteandnullleave the hand cursor intact, so I’m curious how you saw a difference. To my thinking, the best way to avoid the hand cursor when it isn’t wanted is to set theButton.enabled(orMovieClip.enabled) property tofalsefor the object in question. That leaves the event handler intact, but disables it (and the hand) until that property is again set totrue.August 20th, 2006 at 2:05 pm
However in MX 2004, mc.eventhandler does not work with mc.loadMovie, while onClipEvent does. example
mc.onLoad = function() {trace(this._width)}
mc.loadMovie(”images/image.jpg”)
…will not work. In fact …
mc.loadMovie(”images/image.jpg”)
trace(mc._width)
…may not work, even if you wait for the image to complete loading. But…
onClipEvent(load) { trace this._width }
will always work.
Comments?
August 20th, 2006 at 6:39 pm
Nuander,
As it turns out,
MovieClip.onLoadworks just fine. It’s just that this event works differently from the others — and not the way most people expect it to. The documentation isn’t especially clear in this case (my opinion, of course), but look carefully at the entry forMovieClip.onLoad: ” … You use this handler only with movie clips for which you have a symbol in the library that is associated with a class.” In other words, this event must be handled in collaboration with a class that extendsMovieClip. I don’t know why, in particular, that one event is different, but them’s the brakes.December 7th, 2006 at 10:30 am
i got this problem!it might be a nooby problem!
The below code is an action of a movie clip with instance name of “button_mc”,the problem is when its click,it should stay highlight unless a onReleaseOut had been made,it returns to its normal state.
the problem is :
When the button is hightlight and i rolledOut then Over again!the button_mc results a mili-second glitch of OVER state Befor seeing its action script!
ill copy paste the report down under the actionsciprt,it had been driving me crazy!
========================================
var Hit:Boolean;
this.button_mc.onEnterFrame = function() {
if (Hit == true) {
button_mc.gotoAndStop(”_on”);
}
};
this.button_mc.onReleaseOutside = function() {
trace(”——–OUT RELEASE——–”);
Hit = false;
button_mc.gotoAndStop(”_Out”);
}
_root.button_mc.onRollOut = function() {
if (Hit != true) {
trace(”—-(Hit != true) is TRUE—> _OUT”);
button_mc.gotoAndStop(”_out”);
} else {
trace(”Disable _OVER”);
button_mc.gotoAndStop(”_over”);
} else {
trace(”Disable “+Hit);
};
======================================
——————OUTPUT————————
Button Status: _Out
Button Status: _OVER
—-(Hit != true) is TRUE—> _OVER
HIT ====>true
Button Status: Enabled
Button Status: _OVER
December 7th, 2006 at 2:13 pm
3D,
My hunch is, your problem is the result of an unnecessary use of the
MovieClip.onEnterFrameevent. You have so many other useful mouse-related events! — in fact, you’re already using many of them.Rather than waste CPU cycles on a constant
if (Hit == true)loop, check for that Boolean in eitheronRelease,onReleaseOutside, or maybe both. That’s the only time it matters, right? And that way, your code doesn’t depend on a repeating loop, but rather, on a nice, orderly sequence of events, as needed.December 10th, 2006 at 8:10 am
Woh!what a nooby mistake
so i guess i was looping the whole onEnterFrame code!with its button movie clip code re-checking!!
well ppl learn from their mistakes!
damn
December 10th, 2006 at 8:23 am
Well i’d like to ask something!but since this isnt a forum!i was wondern where can i feel free to ask stuff..?
December 10th, 2006 at 12:53 pm
3D,
Haha, that’s how it works … if you find yourself making a mistake, just pick yourself up and keep trying. You’ll figure it out, with enough determination.
The official Adobe forums are good, for sure. And you may also want to check out the new Keyframer forums, hosted by my friend Chris Georgenes.
December 14th, 2006 at 11:30 pm
Hi,
I hope im allowed to ask this here. My question would be how to ‘reenable’ that null button? for example i have a button with rollover effect that nulls after user press. but I want it reactivated again to see that rollover effect.
December 15th, 2006 at 8:46 am
Elkapitan,
That’s a good question. Since you used the word “reenable,” I’d like to point out that the
MovieClipandButtonclasses each feature anenabledproperty, which can be used to toggle an instance’s responsiveness. That isn’t the same as deleting or nulling the function assigned to an event, because the event still occurs whenenabledis false; it’s just that the object ignores it.In order to re-assign an event handler you’ve deleted or nulled, you merely have to repeat what you did in the first place (namely, to assign the event to a function). Obviously, this can get a bit tedious, depending on how often it needs to happen. To save on retyping, I recommend you use a named function rather than a literal function.
At some point later in the ActionScript, you may get rid of the event handler by deleting it …
And if you ever want to add it again, simply to this …
Notice the lack of parentheses after
doSomething, both here and above (the first time the event is handled). That’s because the parentheses actually cause the function to run — and you don’t want to trigger the function here; at this point, you’re merely assigning it to something.August 30th, 2007 at 9:26 am
Looks like flash is moving towards developers rather than designers.
August 30th, 2007 at 11:21 am
markc,
It’s hard for me to judge that assessment, because I really do enjoy both aspects of Flash: designing and developing. If Flash has been moving toward developers (programmers) — and I certainly don’t deny that; just not sure how strongly I would affirm it — the steps away from
on()andonClipEvent()began three full versions ago, back with Flash MX in 2002.The nice part is, if you prefer that paradigm, all you have to do is configure your publish settings for AS1 or 2. Even in Flash CS3, you can stick with the approach that makes you the most comfortable.
September 22nd, 2007 at 2:48 am
Hey, so how would you code a
onClipEvent(enterFrame) {
using your method?
I see you give an example of a mouseUp command, but not an enterFrame command.
September 22nd, 2007 at 2:51 am
and what about onClipEvent (load)?
Thanks
September 25th, 2007 at 3:54 pm
Battletards,
To handle the
enterFrameevent as described above, you would reference the movie clip by its instance name and pretty much code it up the same way:It works the same in all cases except, as coincidence would have it, the
MovieClip.onLoadmethod. For that, check out my “Is the MovieClip.onLoad Event Broken?” article.