AS3 | 1120: Access of undefined property stage - actionscript-3

My goal is to create rectangle as MovieClip with stage size, but Flash gives me this error: 1120: Access of undefined property stage. (on line 6,7,14)
My code:
package {
import flash.display.MovieClip;
public class main {
var mc_background:MovieClip = new MovieClip();
var stageW:Number = stage.stageWidth;
var stageH:Number = stage.stageHeight;
public function main() {
drawBackground();
}
public function drawBackground():void {
mc_background.beginFill(0xFF00CC);
mc_background.graphics.drawRect(0,0,stageW,stageH);
mc_background.graphics.endFill();
stage.addChild(mc_background);
}
}
}

i had a similar problem, the thing is, the stage hasn't really been setup yet, so you need to wait to get data from it or stuff in it. just add this:
protected function addedToStageHandler(event:Event):void
{
//do stuff
}
protected funcion init():void
{
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
//more stuff
}
hope it helps

The stage property of an object isn't defined until the object has been added to the Stage or another object on the Stage.
The constructor of a class is called when the class instance is created, and that is before the instance could have been added to the Stage. So, you can't access stage within code you call from the constructor, or when you define the instance variables stageW and stageH.
To access the stage property as soon as the object is added to the stage, allow the object to handle the ADDED_TO_STAGE event:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class main
{
var mc_background:MovieClip = new MovieClip();
public function main()
{
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
private function addedToStageHandler(event:Event):void
{
// Generally good practice to remove this listener from the object now because it stops addedToStageHandler from being called again if the object is removed and added back to the stage or display list.
removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
drawBackground();
}
private function drawBackground():void {
mc_background.beginFill(0xFF00CC);
mc_background.graphics.drawRect(0,0,stage.stageWidth, stage.stageHeight);
mc_background.graphics.endFill();
addChild(mc_background);
}
}
}

Related

Avoid null object reference errors in code inside the child SWF

I'm creating a global loader that loads different SWFs.
I don't have access to the child SWFs code.
I'm trying to avoid null object reference errors in code inside the child SWF that may reference "stage" etc.
I've added all the possible event listeners, added try/catch, tried all the applicationDomains and LoaderContexts permutations. for example:
applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
var con:LoaderContext = new LoaderContext(false, applicationDomain );
con.allowCodeImport = true;
var _loader:Loader = new Loader();
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoad);
_loader.load( new URLRequest(fileName + ".swf"), con);
I just can't catch the error or disable/remove the code from such a SWF.
for example, the following Main class:
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public function Main() {
var h = this.stage.stageHeight;
trace(h);
}
}
}
will crush any SWF that will try to load it as part of another SWF.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Main()
Any help with catching the Error, disabling/removing the code or any other idea will be much appreciated.
Thanks.
Do you have access to the code in the child swf files? If so, you can do something like this:
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public function Main() {
if (stage) {
init();
}
else {
addEventListener(Event.ADDED_TO_STAGE, init);
}
}
public function init(evt:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// You can now access the stage here
}
}
}
This will hold off initializing the child object until the stage reference is set. For all child objects the constructor will be called first before the stage is set, so you can't rely on it being there in the constructor.

Access of undefined property issues in AS3

I am having a bit of trouble with some AS3. First time using this language and have more experience with web development then OOP so am getting a bit confused.
I am trying to make it so that when someone clicks a 'powerbutton' which is a "movieclip" symbol within flash then another symbol should then become visible. This is all being done within the Kitchen class.
The code for the main class is which i got from a youtube tutorial video i followed;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.events.Event;
import Kitchen
public class DragFood extends MovieClip
{
protected var originalPosition:Point;
var myKitchen:Kitchen
public function DragFood() {
myKitchen = new Kitchen;
originalPosition = new Point (x, y);
buttonMode = true;
addEventListener (MouseEvent.MOUSE_DOWN, down);
}
protected function down (event:MouseEvent):void
{
parent.addChild(this);
startDrag();
stage.addEventListener (MouseEvent.MOUSE_UP, stageUp);
}
protected function stageUp (event:MouseEvent):void
{
stage.removeEventListener (MouseEvent.MOUSE_UP, stageUp);
stopDrag();
if (dropTarget)
{
if(dropTarget.parent.name == "bowl")
{
trace("The " + this.name + " is in the bowl");
this.visible = false;
} else {
returnToOriginalPosition();
}
} else {
returnToOriginalPosition();
}
}
protected function returnToOriginalPosition():void
{
x = originalPosition.x;
y = originalPosition.y;
}
}
}
Within it i call the other class;
import Kitchen
public class DragFood extends MovieClip
{
protected var originalPosition:Point;
var myKitchen:Kitchen
The code for the kitchen class is;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
public class Kitchen extends MovieClip
{
// This is a function. This particular function has the same name as our class and therefore will be executed first
public function Kitchen()
{
// This is a "call" to another function that is defined later in the program.
init();
trace("Hello world");
}
public function init():void
{
// If we want an object (on the screen or otherwise) to be notified about an event we must add a listener for that event to that object.
// We also need to specify what happens everytime the event we are listening for happens.
PowerButton.addEventListener(MouseEvent.CLICK, handleButtonClicks);
}
//This function is called when the oven on button recieves a click.
public function handleButtonClicks(event:MouseEvent):void
{
OvenOn.visible = true;
trace("the oven is being switched on");
}
}
}
The issue i keep getting is that OvenOn and PowerButton are giving me a undefined access issue and im not sure how to fix it. I have found posts on similar subjects like - Access of Undefined property? Actionscript 3
but im not quite sure how to apply it to my issue if anyone could offer any help that would be great.
When you're programming on the timeline, code is referencing the local namespace, and objects you make there (movieclips, textfields, etc.) are automatically instantiated in that namespace so that you can simply call OvenOn.visible = true. However, for each class, their local namespace is whatever is inside the class, so unless you actually created a property on your class called OvenOn, it will most definitely give you Access of Undefined Property errors.
Think of each class as its own island. For them to touch eachother, they need some sort of connection. That connection can be made once the parent instantiates the class in its own namespace. For example...
var foo:String = "Hello!";
var bar:MyClass = new MyClass();
// At this point, whatever code runs inside of MyClass has no concept of foo, or how to access it.
addChild(bar);
// Now that we've added it to the stage, the bar has some properties that have automatically been populated such as "root", "parent", or "stage".
foo.someProperty = "World";
// Since this namespace has a variable pointing to the instance, we can change properties on that class.
Now that we've instantiated MyClass on the stage, we can reference parent properties the class didn't know about. Mind you, this is not necessarily best practice.
package
public class MyClass extends MovieClip {
var someProperty:String = "cheese";
public function MyClass() {
trace(parent.foo) // this will fail
addEventListener(Event.ADDED_TO_STAGE, test);
}
public function test(e:Event):void {
trace(this["parent"].foo); // this will succeed
}
}
}
If you absolutely must change something that is not part of your Kitchen class, pass either the parent of OvenOn or that object specifically as a property of Kitchen. You could do this a couple ways.
with the Constructor...
var something:*;
public function MyClass(someObject:*) {
something = someObject;
}
public function test():void {
something.visible = false;
}
...or by Assigning the Property...
var bar:MyClass = new MyClass();
bar.something = OvenOn;
bar.test(); // will turn off the OvenOn now that 'something' is pointing to it.

AS3 reference custom property in a custom class for a library symbol

So I've done a fair amount of searching through SO and couldn't quite find the answer to this question. I have a movieclip in my symbol library that's exported for actionscript, and I've written a custom class for it. It mostly works great except for when I try to access a custom private property after I've added the movieclip to the stage. Below's an example:
package {
public class MyMovieClip extends MovieClip {
private var _isEnabled:Boolean = false;
public function MyMovieClip():void {
trace(this);
}
public function set isEnabled( b:Boolean ):void {
_isEnabled = b;
}
public function get isEnabled():Boolean {
return _isEnabled;
}
}
}
And then I have another class where I am adding instances of the movieclip to the stage in a loop:
package {
public class MyOtherClass extends MovieClip {
public var myMC:MyMovieClip;
public var docClass:*;
public function MyOtherClass( docRef:* ):void { // passing in a reference to the DocumentClass so I can access the stage
docClass = docRef;
init();
}
public function init():void {
for(var i:int=0; i<6; i++) {
var myMC:MyMovieClip = new MyMovieClip; // instantiate the movieclip which is exported for actionscript and has a custom class
//set a few native properties
myMC.name = "myMC" + i; //setting the name so I can reference this movieclip after it's been added to stage
myMC.y = myMC.height * i + 20;
myMC.x = 20;
myMC.alpha = .7;
}
dispatchEvent(new Event(MyOtherClass.MOVIECLIPS_ADDED)); // just to be safe, let's dispatch a custom event when all movieclips have been added
}
public function traceEnabled():void {
trace(docClass.stage.getChildByName("myMC1").isEnabled); // this throws: 1119: Access of possibly undefined property isEnabled through a reference with static type flash.display:DisplayObject
}
}
}
And finally I instantiate MyOtherClass inside my document class:
package {
public class DocumentClass extends MovieClip {
public var myOtherClass:MyOtherClass;
public function DocumentClass():void {
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
public function onAddedToStage(e:Event):void {
myOtherClass = new MyOtherClass(); // upon instantiation, init is called in MyOtherClass and all of my movieclips are added to the sage
}
}
}
What gives? Why can't I access the MyMovieClip property, isEnabled, after it's been added to the stage? Is there another way? (Thanks in advance for any help)
Internally all children of a DisplayObjectContainer are referenced as DisplayObject, so when you use getChildByName, it returns a DisplayObject.
In order to access your custom properties without causing a compile-time error, you would need to cast the result of getChildByName as the Class of your custom properties. See the code below.
That however isn't your only issue (though it's the reason for the error, once you correct you will get runtime errors as well).
In your creation loop, your not adding myMC to the display list, so calling stage.getChildByName() will return null because your clips aren't on the stage.
Your also not adding your myOtherClass to the display list in the posted code.
Also, storing a reference to the document class isn't really needed. Just add the addedToStage listener in MyOtherClass and have the handler be init.
HERE IS SOME UPDATED CODE
For your MyOtherClass:
public function MyOtherClass():void {
if(stage){
init(); //if stage is ready, call init, if not wait for the added to stage event
}else{
addEventListener(Event.ADDED_TO_STAGE,init);
}
}
public function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE,init);
for(var i:int=0; i<6; i++) {
var myMC:MyMovieClip = new MyMovieClip;
myMC.name = "myMC" + i; //setting the name so I can reference this movieclip after it's been added to stage
myMC.y = myMC.height * i + 20;
myMC.x = 20;
myMC.alpha = .7;
addChild(myMC); //!!!! add to the displayList
}
dispatchEvent(new Event(MyOtherClass.MOVIECLIPS_ADDED)); // just to be safe, let's dispatch a custom event when all movieclips have been added
}
public function traceEnabled():void {
var myMC:MyMovieClip = this.getChildByName("myMC1") as MyMovieClip; //!!! cast it as MyMovieClip so you have access to all the properties/methods in that class
if(myMC){ //myMC will be null if the cast failed
trace(myMC.isEnabled);
}
}
/*
getChildByName is slow and cumbersome. Most people generally only use it for accessing things put on the timeline in the Flash IDE. Using events is a much better way of accessing your items. If traceEnabled was caused by a mouse event attached to myMC, then this would be a much better implementation:
*/
public function betterTraceEnabled(e:Event):void {
var myMC:MyMovieClip = e.currentTarget as MyMovieClip;
if(myMC){
trace(myMC.isEnabled);
}
}
AND YOUR DOCUMENT CLASS:
public class DocumentClass extends MovieClip {
public var myOtherClass:MyOtherClass;
public function DocumentClass():void {
if(stage){
onAddedToStage(null); //most of the time stage is already populated in the constructor of your document class
}else{
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
}
public function onAddedToStage(e:Event):void {
myOtherClass = new MyOtherClass(); // upon instantiation, init is called in MyOtherClass and all of my movieclips are added to the sage
addChild(myOtherClass); //add it to the displayList
}
}

Flash TypeError: Error #1009: Cannot access a property or method of a null object reference. - when accessing TLFTextField from Document Class

I'm lost on this one. I receive a TypeError: Error #1009: Cannot access a property or method of a null object reference. output message the first time my Document Class tries to access a simple textfield on the stage (added from the IDE, not actionscript)
package {
import flash.display.*;
import fl.text.*;
import flash.text.*;
import flash.events.*;
import flash.net.*;
public class Main extends MovieClip {
private var _netConnection:NetConnection;
private var _responder:Responder;
/* some other public + private vars */
public function Main() {
init();
}
public function init(e:*=null):void {
_netConnection = new NetConnection();
_responder = new Responder(uponResult);
txt.text = "init()";
}
/* more functions */
}
}
I tried adding txt.addEventListener(Event.ENTER_FRAME, init); incase the txt TLFTextField wasn't ... there... at the beginning, but it still outputs the error.
I feel like a bit of an idiot atm, what's the prognosis doc?
JB
TLFTextFields are weird creatures, I've had a lot of issues with them recently.
I'd try to use the Event.ADDED_TO_STAGE event because the TLFTextFields have to be on the stage when you try to access them:
public function Main() {
addEventListener(Event.ADDED_TO_STAGE, init);
};
public function init(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
txt.text = "init()";
};
It should work if your TLFTextField is on the first frame on the Main Timeline.
Let me know if this one does the magic,
Rob

AS3 Cannot access stage from custom class

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?
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);
}
}
}
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.
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);
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.
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);
}
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
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