Link to home
Start Free TrialLog in
Avatar of blue-genie
blue-genieFlag for South Africa

asked on

AS3 instantiating of items of stage.

assume you have 3 frames 1st frame stick a button on the stage.
in your document class add listeners for that button to go to frame 3.
at frame 3 using AS3 add another button and make that button take you back to frame 1.
that button in frame 1 loses it's event listener qualities even if you recall a function to set them

can someone verify for me and explain.
i know i'm being lazy dumping the stuff on the stage in the first place.
Avatar of IqAndreas
IqAndreas
Flag of Sweden image

Could you post the exact code you are using to create these buttons, and I can help explain to you how you can modify your code to make it work properly.
That's just weird...  I have never had a chance where I'd put 3 frames in the main FLA, so I thought that you were just crazy, but I have to say that you are sane...  I could reproduce it...  

This sample kinda works, but throws out an error message whenever I go back to the frame 1...  Not sure why it's throwing out an error message though...  :(

Any thoughts, guys???

CyanBlue
FrameTest.zip
@CyanBlue
Sadly, I am unable to open FLA files on this computer. Could you attach the plain code and the full error message?

If you debug using CTRL+SHIFT+ENTER, the console will tell you the EXACT line you get the error at. Then you know where the problem lies.
Sure...  This is the AS file...

CyanBlue
package
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	public class FrameTest extends MovieClip
	{
		var btn0:MovieClip;
		var btn1:MovieClip;
		
		public function FrameTest()
		{
			addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		public function init(e:Event):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			
			addFrameScript(0, onFrame1);
		}
		
		private function onFrame1():void
		{
			stop();
			
			if ((btn0 != null) && btn0.hasEventListener(MouseEvent.CLICK))
			{
				btn0.removeEventListener(MouseEvent.CLICK, onClick_Btn0);
				btn0 = null;
			}
			
			btn0 = getChildByName("button0") as MovieClip;
			btn0.buttonMode = true;
			btn0.addEventListener(MouseEvent.CLICK, onClick_Btn0);
		}
		
		private function onClick_Btn0(e:MouseEvent):void
		{
			gotoAndStop(3);
			
			addFrameScript(2, onFrame3);
		}
		
		private function onFrame3():void
		{
			stop();
			
			if ((btn1 != null) && btn1.hasEventListener(MouseEvent.CLICK))
			{
				btn1.removeEventListener(MouseEvent.CLICK, onClick_Btn1);
				btn1 = null;
			}
			
			btn1 = getChildByName("button1") as MovieClip;
			btn1.buttonMode = true;
			btn1.addEventListener(MouseEvent.CLICK, onClick_Btn1);
		}
		
		private function onClick_Btn1(e:MouseEvent):void
		{
			gotoAndStop(1);
			
			onFrame1();
		}
	}
}

Open in new window

And this is the error message...

CyanBlue
[SWF] Users:CyanBlue:FrameTest:FrameTest.swf - 3340 bytes after decompression
TypeError: Error #1009: Cannot access a property or method of a null object reference.
	at FrameTest/onFrame1()[/Users/CyanBlue/FrameTest/FrameTest.as:35]
	at FrameTest/onClick_Btn1()[/Users/CyanBlue/FrameTest/FrameTest.as:65]

Open in new window

A few things, I'm not sure why you are doing this:
                private function onClick_Btn1(e:MouseEvent):void                {                           gotoAndStop(1);    onFrame1();                }

The gotoAndStop() function should automatically run "onFrame1", so there isn't much use in calling it twice. Have you written the code this way in real life, or just as an example for me? If you are using a document class, you might as well use functions instead of "addFrameScript".


Try the attached script and see if it works. It's a bit messy mixing timeline code and packaged code, but it will have to do. :P



package
{
        import flash.display.MovieClip;
        import flash.events.Event;
        import flash.events.MouseEvent;
        
        public class FrameTest extends MovieClip
        {
                var btn0:MovieClip;
                var btn1:MovieClip;
                
                public function FrameTest()
                {
                        if (stage) 
                           { init(null); }
                        else
                           { addEventListener(Event.ADDED_TO_STAGE, init); }
                }
                
                public function init(e:Event):void
                {
                        removeEventListener(Event.ADDED_TO_STAGE, init);
                        
                        //Only add the frame script ONCE
                        addFrameScript(2, onFrame3);
                        
                        stop();
                }
                
                private function onFrame1():void
                {
                        stop();
                        
                        if (btn0 != null)
                        {
                                //Calling "removeEventListener" even if you don't have the listener attached
                                //will NOT produce an error
                                btn0.removeEventListener(MouseEvent.CLICK, onClick_Btn0);
                        }
                        
                        //If "button0" is not a child, 'btn0' will be null
                        //btn0 = getChildByName("button0") as MovieClip;
                        //Instead try this:
                        btn0 = this.button0;
                        if (btn0)
                        {
                              btn0.buttonMode = true;
                              btn0.addEventListener(MouseEvent.CLICK, onClick_Btn0);
                        else
                        {
                              trace("Button0 is null - not sure why...");
                        }
                }
                
                private function onClick_Btn0(e:MouseEvent):void
                {
                        gotoAndStop(3);
                }
                
                private function onFrame3():void
                {
                        stop();
                        
                        if (btn1 != null)
                        {
                                //Calling "removeEventListener" even if you don't have the listener attached
                                //will NOT produce an error
                                btn1.removeEventListener(MouseEvent.CLICK, onClick_Btn1);
                        }
                        
                        //If "button1" is not a child, 'btn1' will be null
                        //btn1 = getChildByName("button1") as MovieClip;
                        //Instead try this:
                        btn1 = this.button1;
                        if (btn1)
                        {
                              btn1.buttonMode = true;
                              btn1.addEventListener(MouseEvent.CLICK, onClick_Btn1);
                        else
                        {
                              trace("Button1 is null - not sure why...");
                        }
                }
                
                private function onClick_Btn1(e:MouseEvent):void
                {
                        gotoAndStop(1);
                        onFrame1();
                }
        }
}

Open in new window

No, that does not work because onFrame1() is never called unless you specify inside the init() method...  If I throw that into the init(), it works once, but this block gets executed which is basically the same thing why I was scratching my head...
   trace("Button0 is null - not sure why...");

CyanBlue
Avatar of blue-genie

ASKER

hey guys sorry i'm making waves in our AS world.

CB if something is null and you try catch it using if (!null) it throws that error that it's null anyway.
i just make sure the stuff exists.

I know how to overcome this problem in the first place by not adding the stuff to the stage except at runtime , and I had some time this afternoon to rewrite this but I still want to know what that happens.
 
CB i'm glad I'm sane :-)
Yeah, you wouldn't have this problem if you are placing items on the stage dynamically, but that's not the question you asked...  You were having the insane problem with the stuff on the stage which does not make sense...  :(

CyanBlue
it is a weird one - its also odd that it doesn't throw any errors.
Perhaps it has something to do with if all items are placed on the stage again after the frame script has been run? That way, stage items would be null during the frame script execution.

It is horrible timing that I am stuck without Flash Professional now that I need it, but could someone test the attached code and post the results?
package
{
        import flash.display.MovieClip;
        import flash.events.Event;
        import flash.events.MouseEvent;
        
        public class FrameTest extends MovieClip
        {
                var prevEnterFrame:int = -1;
                var prevExitFrame:int = -1;
                
                public function FrameTest()
                {
                        if (stage) 
                           { init(null); }
                        else
                           { addEventListener(Event.ADDED_TO_STAGE, init); }
                }
                
                public function init(e:Event):void
                {
                        removeEventListener(Event.ADDED_TO_STAGE, init);
                        
                        stop();
                        
                        //CLICK THE STAGE IN ORDER TO SKIP FRAMES
                        stage.addEventListener(MouseEvent.CLICK, skipFrames);
                        
                        //Only add the frame script ONCE
                        addFrameScript(0, onFrame1);
                        addFrameScript(2, onFrame3);
                        
                        //I will also listen for enter and exit frames
                        this.addEventListener(Event.ENTER_FRAME, enterFr);
                        this.addEventListener(Event.EXIT_FRAME, exitFr);
                        
                        //Run frame 1 manually
                        onFrame1();
                }
                
                private function skipFrames(ev:MouseEvent)
                {
                        if (this.currentFrame = 1)
                        {
                           gotoAndStop(3);
                           trace(">>GOING TO FRAME 3 ------");
                        }
                        else
                        {
                           gotoAndStop(1);
                           trace(">>GOING TO FRAME 1 ------");
                        }
                }
                
                private function enterFr(ev:Event)
                {
                        if (this.currentFrame == prevEnterFrame)
                           { return; }
                
                        //else - continue the code
                        
                        prevEnterFrame = this.currentFrame;
                        var startText:String = "FRAME" + this.currentFrame + " ENTER_FRAME - ";
                        
                        if (this.button0)
                        {
                           startText += "button0 is NOT null";
                        }
                        else
                        {
                           startText += "button0 is NULL!!";
                        }
                        trace(startText);
                }
                
                private function exitFr(ev:Event)
                {
                        if (this.currentFrame == prevExitFrame)
                           { return; }
                
                        //else - continue the code
                        
                        prevExitFrame = this.currentFrame;
                        var startText:String = "FRAME" + this.currentFrame + " EXIT_FRAME - ";
                        
                        if (this.button0)
                        {
                           startText += "button0 is NOT null";
                        }
                        else
                        {
                           startText += "button0 is NULL!!";
                        }
                        trace(startText);
                }
                
                private function onFrame1():void
                {
                        stop();
                        
                        var startText:String = "FRAME" + this.currentFrame + " FRAMESCRIPT - ";
                        
                        if (this.button0)
                        {
                           startText += "button0 is NOT null";
                        }
                        else
                        {
                           startText += "button0 is NULL!!";
                        }
                        trace(startText);
                }
                
                private function onFrame3():void
                {
                        stop();
                        
                        var startText:String = "FRAME" + this.currentFrame + " FRAMESCRIPT - ";
                        
                        if (this.button1)
                        {
                           startText += "button1 is NOT null";
                        }
                        else
                        {
                           startText += "button1 is NULL!!";
                        }
                        trace(startText);
                }
        }
}

Open in new window

It seems like CS3 does not like Event.EXIT_FRAME event...  :(

CyanBlue
Are you sure? According to the language reference, it did exist in Flash Player 9 (which is what CS3 compiles to by default)
http://help.adobe.com/en_US/AS3LCR/Flash_10.0/flash/events/Event.html#EXIT_FRAME

Or are you saying the results came back poorly for the EXIT_FRAME?


If you are getting any specific error messages, please post them, and I will hunt down the problem.
I get the following error message in CS3 regarding the Event.EXIT_FRAME event...

   1119: Access of possibly undefined property EXIT_FRAME through a reference with static type Class.
addEventListener(Event.EXIT_FRAME, exitFr);

function exitFr(e:Event):void
{
	trace("Hello");
}

Open in new window

I don't get any errors.
(after fixing basic typo that is)
and it does work it's ridiculous that you need to do so much work to get something so basic to work.

just want to fiddle with the code a bit, will get back to you guys now.
So, what were the trace results of the code?

The code I supplied wasn't meant to fix the problem, but to help debug the order in which items are placed on the stage via the timeline, compared to the order when the scripts run.
oh oops, i just made some changes to add the click listeners to some buttons and they worked.


on load

FRAME1 FRAMESCRIPT - button0 is NOT null
FRAME1 FRAMESCRIPT - button0 is NOT null
FRAME1 EXIT_FRAME - button0 is NOT null
FRAME1 ENTER_FRAME - button0 is NOT null

that what you want?
a case of you don't know your own genius :-)

back to the point, you're right, we're not trying to fix it as much as trying to know why it needs to be fixed.
Yes, that is the code I want. If you click the stage, it should jump to frame 3, and when clicked again, jump back to frame 1, tracing out the necessary information. Could you post the resulting data here?

Sorry I can't test it myself, Flash Professional is pretty much impossible to get working in Linux
http://iqandreas.blogspot.com/2010/03/flexflash-builder-on-linux.html


So you made changes to fix it which worked? What did you do?


"a case of you don't know your own genius :-)" - I don't quite understand what you mean by this. :P


all i did was put the listeners on the button as my original query.

so i think that addScript / frame thing is the key but there's no logical reason why it does that because in theory those listeners should be in scope until they're removed right?

curiouser and curiouser

It is logical that it is the insane thing that's happening...  It is not logical that it is doing what it is not supposed to be doing...  :p

In theory, yes the listener should stay as long as I don't tell it do be gone or when the garbage control system somehow zaps it...

One thing we all should learn from this is that we have to stay away from the multi frame movies as much as possible...  :p

Oh, I did create a new FLA in CS4 and tested the Event.EXIT_FRAME which worked fine...  I don't know why it did not work on CS3...  I thought that I have applied the updater last time...  I'll have to double check on that...  
@blue-genie...  Are you on CS3???  What does the version say???

CyanBlue
i tried it on CS4.

will go try now on CS3 - just for laughs.

re. One thing we all should learn from this is that we have to stay away from the multi frame movies as much as possible...  :p
I agree I know I was lazy have learned my lesson I am sorry will never give myself such pain again it's just not worth it but i still want to know what it does that stupid flash.
okay learned something new

apparently Adobe lied. EXIT_FRAME is only available for FP10 not FP9 , so in CS3 you can only export up to FP9 - throws error.


Interesting...  Bad Adobe, Bad...  :p

CyanBlue
I have always wondered, let's say you create "button0" on frame 1.

You go to frame 3, and button0 is removed from the display list and the "this.button0" is set to null.

If you navigate back to frame 1, is that same instance old instance of "button0" as before, or does Flash create a NEW instance and place it on the stage? If so, that would explain the listeners, and if the frame script is run BEFORE the stage is populated with all frame 1's display objects, then "button0" would be null when the script is run, and therefore never get the addEventListener attached to it.


But I am having a little difficult following what is going on (maybe because it's getting quite late...)
Anyone want to do a quick summary? :P
ASKER CERTIFIED SOLUTION
Avatar of CyanBlue
CyanBlue
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I see the problem in your code.
gotoAndStop(1);onFrame1();

The way that Flash works is when you get a "gotoAndStop" command, it doesn't switch to that frame immediately. Instead Flash says, "Okay, I will keep in mind that the next time I switch to a frame, I will go to frame 1. HOWEVER, first I will finish ALL the code on the current Frame.

So Flash remembers that, and then says, "Okay, now I will run onFrame1", so he runs the function. HOWEVER, since he's technically not on frame 1 yet, button0 will be NULL! This is terrible!

When ALL the code has finished running, Flash remembers to switch frames. He goes to frame 1, and realizes that he is supposed to run "onFrame1" due to there being a previous "addFrameScript". This time (since he now really IS on frame 1), button0 is NOT null. :)


That explains why the code runs twice. And remember, that first, you run frame 1 when you first start the code. (hence trace #1, and button0 is not null). Then you go to frame 3. And finally, you go back to frame 1, however, as I described, you run the frame 1 code twice, so it traces first "trace #2, and since you are not yet actually on frame 1, the button is null", and then you actually go to frame 1, which adds "trace #3, where button0 is no longer null."


Am I making myself clear? Ugh... I hope it the solution to this entire ordeal wasn't this simple in the first place. :P I think I'll go kick myself...
Oh, yeah...  I forgot about that...  Yes, that does make sense, but why it is not running the onFrame1 function twice rather run half way and stops???  I am saying that because you should see the trace line 4 times if it were to run twice, but I see 3 trace lines...

Can you update the sample file when you get your Flash/Flex/Linux problem situated???  I think we all need to be on the same page cuz this is confusing...  

Thanks...

CyanBlue
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
IqAndreas, that does work.

the explanation makes sense to me if we say the item gets removed and reinstantiated on frame 1 but if i explicitly set the listeners again it still doesn't seem to work.

i'm going to play around with this some more and see if i get a definitive answer.
i'm going to leave this open for now but if you guys are done let me know and I'll close.

thanks.
thanks all. that was fun.