As with any function, the statements in an event handler execute within a predefined scope. Scope dictates where the interpreter looks to resolve the variables, subfunctions, objects, or properties referenced in an event handler's body. We'll consider event handler scope in relation to movie clip events, button events, and other object events.
Unlike regular functions, movie clip event handlers do not define a local scope ! When we attach a handler to a clip, the scope of the handler is the clip, not just the event handler itself. This means that all variables are retrieved from the clip's timeline. For example, if we attach an enterFrame event handler to a clip named navigation and write trace(x); inside the handler, the interpreter looks for the value of x on navigation's timeline:
onClipEvent (enterFrame) { trace(x); // Displays the value of navigation.x }
The interpreter does not consult a local scope first because there is no local scope to consult. If we write var y = 10; in our handler, y is defined on navigation's timeline, even though the var keyword ordinarily declares a local variable when used in a function.
The easiest way to remember the scope rules of a clip event handler is to treat the handler's statements as though they were attached to a frame of the handler's clip. For example, suppose we have a clip named ball that has a variable called xVelocity in it. To access xVelocity from inside a ball event handler, we simply refer to it directly, like this:
onClipEvent (mouseDown) { xVelocity += 10; }
We don't have to supply the path to the variable as _root.ball.xVelocity because the interpreter already assumes we mean the variable xVelocity in ball. The same is true of properties and methods; instead of using ball._x, we simply use _x, and instead of using ball.gotoAndStop(5), we simply use gotoAndStop(5). For example:
onClipEvent (enterFrame) { _x += xVelocity; // Move the ball gotoAndPlay(_currentframe - 1); // Do a little loop }
We can even define a function on ball using a function declaration statement in a handler, like this:
onClipEvent (load) { function hideMe( ) { _visibility = 0; } }
It's sometimes easy to forget that statements in clip event handlers are scoped to the clip's timeline, not the handler function's local scope and not the clip's parent timeline (the timeline upon which the clip resides).
For example, suppose we place our ball clip on the main timeline of a movie, and the main timeline (not ball's timeline) has a moveBall( ) function defined on it. We may absent-mindedly call moveBall( ) from an event handler on ball like this:
onClipEvent (enterFrame) { moveBall( ); // Does nothing! There's no moveBall( ) function in ball. // The moveBall( ) function is defined on _root }
We have to explicitly refer to the moveBall( ) function on the main timeline using _root like this:
onClipEvent (enterFrame) { _root.moveBall( ); // Now it works! }
Occasionally, we may need to refer to the current clip object explicitly from within an event handler. We can do so using the this keyword, which refers to the current movie clip when used in an event handler. Hence, the following references are synonymous within a clip event handler:
this._x // Same as next line _x this.gotoAndStop(12); // Same as next line gotoAndStop(12);
Use of this is most frequently required when we're dynamically generating the name of one of the current clip's properties (either a variable name or a nested clip). Here we tell one of the nested clips in the series ball.stripe1, ball.stripe2, . . . to start playing, depending on the current frame of the ball clip:
onClipEvent (enterFrame) { this["stripe" + _currentframe].play( ); }
The keyword this is also frequently used with movie clip methods that demand an explicit reference to a movie clip object upon invocation. Any movie clip method with the same name as an ActionScript global function must be used with an explicit clip reference. The this keyword is therefore necessary when invoking the following functions as methods inside an event handler:
duplicateMovieClip( )
loadMovie( )
loadVariables( )
print( )
printAsBitmap( )
removeMovieClip( )
startDrag( )
unloadMovie( )
For example:
this.duplicateMovieClip("ball2", 1); this.loadVariables("vars.txt"); this.startDrag(true); this.unloadMovie( );
We'll learn all about the dual nature of these functions in Section 13.8.3.1, "Method versus global function overlap issues", in Chapter 13, "Movie Clips".
Note that the this keyword allows us to refer to the current clip even when that clip has no assigned instance name in the authoring tool or when we don't know the clip's name. In fact, using this, we may even pass the current clip as a reference to a function without ever knowing the current clip's name. Here's some quite legal (and quite elegant) code to demonstrate:
// CODE ON MAIN TIMELINE // Here is a generic function that moves any clip function move (clip, x, y) { clip._x += x; clip._ y += y; } // CODE ON CLIP // Call the main timeline function and tell it to move the // current clip by passing a reference with the this keyword onClipEvent (enterFrame) { _root.move(this, 10, 15); }
WARNING
In build 30 of the Flash 5 Player, a bug prevented gotoAndStop( ) and gotoAndPlay( ) from working inside a clip handler when used with string literal labels. Such commands were simply ignored. For example, this would not work:
onClipEvent(load) { gotoAndStop("intro"); // Won't work in Flash 5 r30 }To work around the bug, use a self-reflexive clip reference, as in:
onClipEvent(load) { this.gotoAndStop("intro"); }
Button handlers are scoped to the timeline upon which the button resides. For example, if we place a button on the main timeline and declare the variable speed in a handler on that button, speed will be scoped to the main timeline ( _root):
// CODE FOR BUTTON HANDLER on (release) { var speed = 10; // Defines speed on _root }
By contrast, if we place a movie clip, ball, on the main timeline and declare the variable speed in a handler of ball, speed is scoped to ball:
// CODE FOR ball HANDLER on (load) { var speed = 10; // Defines speed on ball, not _root }
Inside a button handler, the this keyword refers to the timeline on which the button resides:
on (release) { // Make the clip on which this button resides 50% transparent this._alpha = 50; // Move the clip on which this button resides 10 pixels to the right this._x += 10; }
Unlike movie clip and button handlers, event handlers attached to instances of built-in classes such as XML and XMLSocket are scoped exactly like functions. An XML or XMLSocket object's event handler has a scope chain that is defined when the handler function is defined. Furthermore, XML and XMLSocket event handlers define a local scope. All the rules of function scope described in Section 9.7, "Function Scope" in Chapter 9, "Functions", apply directly to event handler functions attached to objects that are neither buttons nor movie clips.
Copyright © 2002 O'Reilly & Associates. All rights reserved.