Sprite のコンストラクタから stage を確実に取得する方法

Sprite を継承したクラスのコンストラクタから、stage プロパティを参照するときの注意点。

次のような Test.as を単体でコンパイルして SWF を生成すると問題なく動きます。

package{
    import flash.display.Sprite;

    public class Test extends Sprite
    {
        public function Test()
        {
            trace(stage.stageWidth);
        }
    }
}

ところが、Test.as を別のクラスから作成すると実行時エラーとなってしまいます。

    function foo():void
    {
        // !!! Error !!!: stage is null
        var test:Test = new Test();
    }

理由は単純。別のクラスから test インスタンスが作成された段階では、test インスタンスはステージ上に存在しないため、stage プロパティは null が返されるのです。

stage プロパティが null でなくなるのは、test インスタンスが addChild されてステージ上に現れた後になります。

そこで、次のように addChild されたときに通知を受けられるよう、Test.as を書き換えれば、無事問題は解決します。

package{
    import flash.display.Sprite;
    import flash.events.Event;

    public class Test extends Sprite
    {
        public function Test()
        {
            if(stage)
            {
                trace(stage.stageWidth);
            }
            else
            {
                addEventListener(Event.ADDED, addedHandler);
            }
        }

        private function addedHandler(e:Event):void
        {
            removeEventListener(Event.ADDED, addedHandler);
            trace(stage.stageWidth);
        }
    }
}

root や parent を取得する場合も、このテクニックが使えますね。

頻繁に追加・削除される表示オブジェクトの場合には、この Event.ADDED および Event.REMOVED のお世話になりそうです。

Flex の場合は、UIComponent の mx.events.FlexEvent.ADD イベントをハンドルしたほうがいいのかもしれません。 このへんはよく分かってないので、コメントいただければ幸い...

補足 (2007.06.09)

add で待機せずに stage を取得する方法があるようです。なるほど、確かにこれなら動きますね。