开发者

ActionScript: How to instantiate a Sprite subclass that adds itself to the stage?

I've created a wrapper around Sprite called ClickableCircle, which is meant to add itself to the display list when instantiated. Here's a toy version:

public class ClickableCircle extends Sprite {
    protected var circle:Shape;
    protected var myName:String;

    public function ClickableCircle(name:String, x:uint, y:uint) {
        super();
        circle:Shape = new Shape();
        circle.graphics.beginFill(0x00ACDC, 1);
        circle.graphics.drawCircle(0, 0, 12);
        this.myName = name;
        this.x = x;
        this.y = y;
        this.addChild(circle);
        this.addEventListener(MouseEvent.CLICK, reportClickedID);
        // Here's the problematic line: can't add itself to display list
        // Error #1009: Cannot access a property or method of a null object reference.                                  
        stage.addChild(this);   
        trace("Created " + name + " at " + Stri开发者_StackOverflow中文版ng(x) + ", " + String(y));
    } 

    private function reportClickedID(e:MouseEvent):void {
        trace("You just clicked on " + this.myName);
    }
}

The problem is that when a ClickableCircle is instantiated from the main application, it crashes when it tries to add itself to the stage, bc stage is null. If, on the other hand, the addChild() is commented out from the ClickableCircle constructor, and the instantiated cs is instead added to the display list at the main application level, everything works fine:

public class GreetingApp extends Sprite {
    public function GreetingApp() {
        var cs:ClickableCircle = new ClickableCircle("joe", 100, 200);

        // If the child is added here, everything works.
        stage.addChild(cs);
    }
}

Since both GreetingApp and ClickableCircle extend Sprite, I would think the stage would be instantiated and accessible in both places. I'm brand new to ActionScript/Flex, so I'm sure I'm doing something stupid. Can anyone tell me what it is?


You are correct, stage would be null. The reason is because DisplayObjects only have an implicit reference to stage once they are added to the display list. In your case, this creates a bit of a catch-22.

There are at least a couple ways around this problem.


Option 1: Pass a reference to the stage in your constructor. So something like

var cs:ClickableCircle = new ClickableCircle("joe", 100, 200, stage);

Now in your ClickableCircle instance, you have access to the stage. I would typically use it like this

public function ClickableCircle(name:String, x:uint, y:uint, target:*) {
    ...
    target.addChild(this);
}

Option 2. You can use a static variable with a reference to the stage from your main application class. Or, likewise, you can use a singleton that is instantiated before you create your ClickableCircle and pass the reference to the stage to the singleton. Then you can access it from anywhere.

public static var STAGE:DisplayObjectContainer;

Then, assuming you class is called Main, you could do this in your ClickableCircle class:

Main.STAGE.addChild(this);

If this doesn't make sense or you need more help, let me know.


In fact, a useful utility is a sort of StageManager that is set from your Main Application Sprite/MovieClip/DisplayObject. You can type the accessor to Stage as that is the more appropriate Class Type.

private var _stage:Stage;

public static function get stage() : Stage
{
    if( stage == null ) throw new Error( "You must set the stage in your root before trying to access it." );    
    return stage;
}

public static function set stage( value:Stage )
{
    _stage = value;
}

This is a reasonable singleton to make, as there is only one Stage instance in every application.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜