AS3 Cannot access stage from custom class

2019-07-20 04:22发布

问题:

How can I access the stage and especially the width and mouse position of the flash Movie from a custom class?

package classes
{
   import flash.events.*;
   import flash.display.*;

   public class TableManager extends Sprite
   {
        public function TableManager() {
            sayStage();
        }
        public function sayStage():void 
        {
            trace(stage);
        }
  }   
} 

This will only return nill. I know that DisplayObjects don't have any stage until they have been initiated so you can't access the stage in your constructor but even if I call sayStage() later as an instance method it won't work.

What am I doing wrong?

回答1:

If TableManager is on the stage you can access the stage with this.stage.

The trick is you have to wait for the instance to be added to the stage. You can listen for the ADDED_TO_STAGE event so you know when that's happened.

package classes {
import flash.events.*;
import flash.display.*;

public class TableManager extends Sprite {
    public function TableManager() {
        this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
    }

    private function onAddedToStage(e:Event):void {
        this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
        sayStage();
    }

    public function sayStage():void {
        trace(this.stage);
    }
}   
}


回答2:

The most defensive way to write this is:

public function TableManager() {
    if(this.stage) init();
    else this.addEventListener(Event.ADDED_TO_STAGE, init);
}

private function init(e:Event = null):void {
    if(e != null) this.removeEventListener(Event.ADDED_TO_STAGE, init);
    sayStage();
}

If the object is already on the stage at the time of initialization, then immediately call the init function with no arguments. If not wait until its been added to the stage. Then when the init function gets called, if it was called as the result of an event, then detach the event handler, and move along.



回答3:

You can pass a reference of the root movieclip (i.e. the stage) to your custom class.

e.g.

package classes
{
   import flash.events.*;
   import flash.display.*;

   public class TableManager extends Sprite
   {
       private var _rootMC:MovieClip; 

       public function TableManager(rootMC:MovieClip) {
            _rootMC = rootMC;
            sayStage();
        }
        public function sayStage():void 
        {
            trace(_rootMC.stage);
            trace(_rootMC.stage.stageWidth);
        }
  }   
} 

Then when instantiating your instance of TableManager from the root timeline:

//the keyword 'this' is the root movieclip.
var newTM:TableManager = new TableManager(this);


回答4:

stage will be null as long as the Sprite hasn't been added to the display list - it's nothing to do with initiation. E.g.

var t:TableManager = new TableManager;
stage.addChild( t ); // or your root class, or any class that's already on the displaylist
trace( t.stage ); // [Stage stage]
t.parent.removeChild( t );
trace( t.stage ); // null

As @crooksy88 suggests, either pass in the stage to the constructor, or keep it as a static somewhere, say your main document class, so that you can access it everywhere.



回答5:

i think usefull for You should be create static reference to stage :

in Your main class add line and set stage :

public static var stage:Stage;
...
public function Main():void { // constructor
     Main.stage = stage;
     ...

and than in custom class :

public function sayStage():void 
        {
            trace(Main.stage);
            trace(Main.stage.stageWidth);
        }


回答6:

you may access this.stage when the current object(also a sprite) is already attached to the stage.

public class TableManager extends Sprite{
    public function TableManager()
    {
    }
    public function sayStage():void 
    {
        trace(stage);
    }
}
TableManager tm=new TableManager();
//tm.sayStage();  // no
addChild(tm);  
tm.sayStage();  // fine

hope this could help



回答7:

here is a pretty good solution you only need to reference the stage inside your class you just pass it as a simple object, here how to do that

package  {

    public class Eventhndl{

        private var obj:Object;

        public function Eventhndl(objStage:Object):void{
            obj = objStage;

            trace(obj); // now the obj variable is a reference to the stage and you can work as normal you do with stage (addChild, Events Etc..)

        }

}

this is how you make instance to run it, i have used the constructor method but you can change it to any function as you wish and call it whenever you need it.

import Eventhndl;

var EH:Eventhndl = new Eventhndl(stage);

here is some few Examples how to access stage from class

https://stackoverflow.com/a/40691908/1640362

https://stackoverflow.com/a/40691325/1640362