-
[RESOLVED] Essential ActionScript 3 error #1009
Hi all,
I'm trying to follow the Essential ActionScript 3.0 book and I've hit a snag in chapter 22 at the CustomMousePointerDemo class. I'm using CS4 to compile with a CustomMousePointerDemo as the document class. I get this:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at StageDetector/registerListeners()
at StageDetector/setWatchedRoot()
at StageDetector/setWatchedObject()
at StageDetector()
at CustomMousePointer()
at CustomMousePointerDemo()
when I try to test the movie.
here is the CustomMousePointerDemo
Code:
// File CustomMousePointerDemo.as
package {
import flash.display.*;
// Demonstrates the use of the CustomMousePointer class
public class CustomMousePointerDemo extends Sprite{
private var pointer:CustomMousePointer;
// Constructor
public function CustomMousePointerDemo(){
// Create a new CustomMousePointer object and add it to the display list. The act of
// adding the customMousePointer to the display list automatically replaces the system mouse pointer
// with the CustomMousePointer object
pointer = new CustomMousePointer();
addChild(pointer);
}
}
}
The StageDetector class uses the stage instance variable to determine whether an object is on the display list or not. My guess is that this is where the problem is but I can't figure out why. Here is the StageDetector
Code:
// File StageDetector.as
package {
import flash.display.*;
import flash.events.*;
// Monitors a specified display object to see when it is added to or removed from the stage, and broadcasts the corresponding custom events
// StageDetector.ADDED_TO_STAGE and StageDetector.REMOVED_FROM_STAGE.
// USAGE:
// var stageDetector:StageDetector = new StageDetector(someDisplayObject);
// stageDetector.addEventListener(StageDetector.ADDED_TO_STAGE, addedToStageListenerFunction);
// stageDetector.addEventListener(StageDetector.REMOVED_FROM_STAGE, removedFromStageListenerFunction);
public class StageDetector extends EventDispatcher {
// Event Constants
public static const ADDED_TO_STAGE:String = "ADDED_TO_STAGE";
public static const REMOVED_FROM_STAGE:String = "REMOVED_FROM_STAGE";
// The object for which ADDED_TO_STAGE and REMOVED_FROM_STAGE events will be generated
private var watchedObject:DisplayObject = null;
// The root of the display hierarchy that contains watchedObject
private var watchedRoot:DisplayObject = null;
// Flag indicating whether watchedObject is currently on the display list
private var onStage:Boolean = false;
// Constructor
public function StageDetector(objectToWatch:DisplayObject) {
// Begin monitoring the specified object
setWatchedObject(objectToWatch);
}
// Begins monitoring the specified object to see when it is added to or removed from the display list
public function setWatchedObject(objectToWatch:DisplayObject):void {
// Track the object being monitored
watchedObject = objectToWatch;
// Note whether watchedObject is currently on the display list
if (watchedObject.stage != null) {
onStage = true;
}
// Find the root of the display hierarchy containing the watchedObject, and register with it for ADDED/REMOVED events.
// By observering where watchedObject's root is added and removed we'll determin whether watchedObject is on or
// off the display list.
setWatchedRoot(findWatchedObjectRoot());
}
// Returns a reference to the object being monitored
public function getWatchedObject():DisplayObject {
return watchedObject;
}
// Frees this StageDetector object's resources. Call this before discarding a StageDetector object.
public function dispose():void {
clearWatchedRoot();
watchedObject = null;
}
// Handles Event.ADDED events targeted at the root of watchedObject's display heirarchy
private function addedListener(e:Event):void {
// If the current watchedRoot was added...
if(e.eventPhase == EventPhase.AT_TARGET) {
// ...check if watchObject is now on the display list
if(watchedObject.stage != null) {
// Note that watchedObject is now on the display list
onStage = true;
// Notify listeners that watchedObject is now on the display list
dispatchEvent(new Event(StageDetector.ADDED_TO_STAGE));
}
// watchedRoot was added to another container, so there's now a new root of the display hierarchy containing watchedObject
// Find that new root, and register with it for ADDED and REMOVED events.
setWatchedRoot(findWatchedObjectRoot());
}
}
// Handles Event.REMOVED events for the root of watchedObject's display hierarchy
private function removedListener(e:Event):void {
// If watchedObject is on the display list...
if(onStage) {
//...check if watchedObject or one of it's ancestors was removed
var wasRemoved:Boolean = false;
var ancestor:DisplayObject = watchedObject;
var target:DisplayObject = DisplayObject(e.target);
while (ancestor != null) {
if (target == ancestor) {
wasRemoved = true;
break;
}
ancestor = ancestor.parent;
}
// If watchedObject or one of it's ancestors was removed
if(wasRemoved){
//...register for ADDED and REMOVED events from the removed object
// Which is the new root of watchedObject's display hierarchy
setWatchedRoot(target);
// Note that watchedObject is not on the display list anymore
onStage = false;
// Notifiy listeners that watchedObject was removed from the stage
dispatchEvent(new Event(StageDetector.REMOVED_FROM_STAGE))
}
}
}
// returns the root of the display hierarchy that currently contains watchedObject
private function findWatchedObjectRoot():DisplayObject {
var watchedObjectRoot:DisplayObject = watchedObject;
while(watchedObjectRoot != null){
watchedObjectRoot = watchedObjectRoot.parent;
}
return watchedObjectRoot;
}
// Begins listening for ADDED and REMOVED events targeted at the root of watchedObject's display hierarchy
private function setWatchedRoot (newWatchedRoot:DisplayObject):void {
clearWatchedRoot();
watchedRoot = newWatchedRoot;
registerListeners(watchedRoot);
}
// Removes event listeners from watchedRoot, and removes this StageDetector's reference to watchedRoot
private function clearWatchedRoot():void {
if (watchedRoot != null) {
unregisterListeners(watchedRoot);
watchedRoot = null;
}
}
// Registers ADDED and REMOVED event listeners with watchedRoot
private function registerListeners(target:DisplayObject):void {
target.addEventListener(Event.ADDED, addedListener);
target.addEventListener(Event.REMOVED, removedListener);
}
// Unregisters ADDED and REMOVED event listeners from watchedRoot
private function unregisterListeners(target:DisplayObject):void {
target.removeEventListener(Event.ADDED, addedListener);
target.removeEventListener(Event.REMOVED, removedListener);
}
}
}
I'm pretty sure that there are Event.addedToStage and Event.removedFromStage event types now but I wanted to keep with the book.
Thank you for your help.
-
You left out the class which actually has the error. But I can guess it anyway. In the constructor for CustomMousePointer you have a line like this:
Code:
StageDetector.registerListeners(stage);
Though that seems silly, since the whole point of StageDetector seems to be to do stuff when something is added to the stage, and the stage can't be added to the stage.
Post the constructor of CustomMousePointer. And you're right, there are ADDED_TO_STAGE and REMOVED_FROM_STAGE events which you should use in place of this StageDetector thing.
-
Hi 5TonsOfFlax,
Thank you for your reply. I left out the CustomMousePointer class cause all it does is pass a reference of itself to a StageDetector instance. It looks like this:
Code:
var stageDetector:StageDetector = new StageDetector(this);
stageDetector.addEventListener(StageDetector.ADDED_TO_STAGE, addedToStageListener);
stageDetector.addEventListener(StageDetector.REMOVED_FROM_STAGE, removedFromStageListener);
I think I will have to fore go the StageDetector and just define listener's for the built in events instead. See if that works.
Thanks again!
Justin
-
Ah, now that I actually trace through StageDetector, I see the problem. It's in findWatchedObjectRoot. Since the object passed in has no parent at the time, it should be the watchedObjectRoot, but that function actually returns null in that case. That null is then passed to registerListeners, causing the error.
It could be fixed like this:
Code:
// returns the root of the display hierarchy that currently contains watchedObject
private function findWatchedObjectRoot():DisplayObject {
var watchedObjectRoot:DisplayObject = watchedObject;
while(watchedObjectRoot.parent != null){
watchedObjectRoot = watchedObjectRoot.parent;
}
return watchedObjectRoot;
}
But yeah, use the built in events instead.
-
AH of course! Thank you! And now that I know where to look I realize that I forgot the ".parent"; it was written in the book! I'll have to be more careful
Thanks!
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|