Reputation: 47
Resolved - Solution with example handlers at the bottom.
Is there a way to stop the ADDED_TO_STAGE event firing multiple times.
I've noticed that by loading an external preLoader which loads my Main file, any subsequent Movieclips added to the stage or nested fire multiple times depending upon the depth.
preLoader Main - (Add to stage) UINav In UINav class (add any button or MovieClip)
If I test the MovieClip from the Main, Result Main fires once, UINav fires once, but any objects within UINav or beyond fire twice, or three times depending upon their depth.
If I test the MovieClip from the preLoader, Result Main fires once, UINav fires once,but any objects within UINav or beyond fire three or four times depending upon their depth.
preloader Class :
package
{
public class preLoader extends MovieClip
{
public function preLoader()
{
if( stage ) added( null );
else
addEventListener( Event.ADDED_TO_STAGE, added );
}
private function added( event:Event ):void
{
stage.removeEventListener( Event.ADDED_TO_STAGE, added );
stage.removeEventListener( Event.ADDED_TO_STAGE, init );
trace( "preSite : "+ getQualifiedClassName( this ), "Initiated" );
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.stageFocusRect = false;
//loadStatusTxt on stage
//preLoadText on stage
var loader : Loader = new Loader();
_targetLoaderInfo = loader.contentLoaderInfo;
_targetLoaderInfo.addEventListener( ProgressEvent.PROGRESS, onProgress );
_targetLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, errorIOHandler);
_targetLoaderInfo.addEventListener( Event.COMPLETE , onLoaded );
if( Capabilities.playerType != "External" )
{
loader.load( new URLRequest("Main.swf?id=" + myIdentifier) );
} else {
loader.load( new URLRequest("Main.swf") );
}
}
private function errorIOHandler( event:IOErrorEvent ):void
{
trace( event.text );
}
private function onProgress( event:ProgressEvent ):void
{
var loaded : uint = event.bytesLoaded;
var total : uint = event.bytesTotal;
var percentLoaded:Number = Math.round( (loaded/total) * 100 );
preLoadText.text = "Loading " + percentLoaded + "%";
addChild( preLoadText );
pLoader.x = stage.stageWidth / 2;
pLoader.y = stage.stageHeight - 50;
addChild( pLoader );
_loadPercent = _targetLoaderInfo.bytesLoaded / _targetLoaderInfo.bytesTotal;
updateLoader( _targetLoaderInfo.bytesLoaded / _targetLoaderInfo.bytesTotal );
if ( _loadPercent >= 100 )
{
onLoaded( event );
}
}
private function updateLoader( num:Number ) : void {
//num is a number between 0 and 1
pLoader.mcPreloaderBar.width = num * 476;
}
private function onLoaded( e:Event ):void
{
_targetLoaderInfo.removeEventListener( ProgressEvent.PROGRESS, onProgress );
_targetLoaderInfo.removeEventListener( IOErrorEvent.IO_ERROR, errorIOHandler );
_targetLoaderInfo.removeEventListener( Event.COMPLETE , onLoaded );
// TODO hide loader
removeChild( pLoader );
while ( this.numChildren > 0 )
{
this.removeChildAt( 0 );
}
this.addChild( DisplayObject(LoaderInfo(e.target).content) );
trace( "Class "+ getQualifiedClassName( this ), " - COMPLETE" );
}
}//End Class
}// End Package
Main Class :
package com.misoLepto {
public class Main extends MovieClip
{
public static var test_Main : Boolean = true;// true = Live / false = TraceEvents
public var site_Background : Site_Background = new Site_Background();
public var site_UINav : Site_UINav = new Site_UINav();
public function Main()
{
if ( stage ) init();
else addEventListener( Event.ADDED_TO_STAGE, init );
}
public function init( event : Event = null):void
{
if( hasEventListener( Event.ADDED_TO_STAGE ))
{
stage.removeEventListener( Event.ADDED_TO_STAGE, init );
trace( "YES Listener Main" );
}
else
{
trace( "NO Listener Main" );
}
GlobalVariable.stage = stage;
//stage.removeEventListener(Event.ADDED_TO_STAGE, init);
stage.addEventListener( Event.RESIZE, resizeMain );
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
setupMain();
}
private function toggleUINav( e:Event ):void {
if( site_UINav.stage )
{
removeChild( site_UINav );
}
else
{
addChild( site_UINav );
}
}
private function setupMain():void
{
addChild( site_UINav );
stage.addEventListener( MouseEvent.CLICK, toggleUINav );
}
private function resizeMain( event : Event ) : void
{
trace("Resized Stage");
}
}//End Class
}//End Package
UINav CLass :
package com.misoLepto {
public class Site_UINav extends MovieClip {
public var site_Header : Site_Header = new Site_Header()
public function Site_UINav()
{
if ( stage ) initUINav();
else addEventListener( Event.ADDED_TO_STAGE, initUINav, false, 0, true );
addEventListener( Event.REMOVED_FROM_STAGE, removedUINav );
}
public function initUINav( event : Event = null ):void
{
stage.removeEventListener( Event.ADDED_TO_STAGE, initUINav );
stage.addEventListener( Event.RESIZE, resizeUINav );
setupUINav();
}
private function setupUINav():void {
trace("UINav : Initiated");
addChild( site_Header );
}
private function resizeUINav( event : Event ) : void
{
trace("Resized Stage");
}
private function removedUINav ( event : Event ):void
{
stage.removeEventListener( Event.RESIZE, resizeUINav );
stage.removeEventListener( Event.REMOVED_FROM_STAGE, removedUINav );
removeChild( site_Header );
}
}//End Class
}//End Package
Site Header Class :
package com.misoLepto {
public class Site_Header extends Sprite {
public var headPanel : Sprite = new Sprite();
public var lineColour : uint = new uint( 0x999999 );
public var lineWidth : Number = new Number( 1 );
public var headerColour : uint = new uint( 0xFFFFFF );
public function Site_Header ()
{
if ( stage ) initHeader();
else
addEventListener( Event.ADDED_TO_STAGE, initHeader, false, 0, true );
addEventListener( Event.REMOVED_FROM_STAGE, removedHeader );
}
public function initHeader ( e : Event = null ):void
{
stage.removeEventListener( Event.ADDED_TO_STAGE, initHeader );
stage.addEventListener( Event.RESIZE, resizeHeader );
headPanel.graphics.lineStyle( lineWidth, lineColour );
headPanel.graphics.beginFill( headerColour, 1 );
headPanel.graphics.drawRoundRect( stage.stageWidth / 2, 2, stage.stageWidth / 2 - 3, 25, 10 );
headPanel.graphics.endFill();
trace( "HeaderPanel : Initialised" );
addChild(headPanel);
setupHeader();
}
public function resizeHeader( event : Event ) : void
{
if ( headPanel.stage )
{
headPanel.graphics.clear();
headPanel.graphics.lineStyle( lineWidth, lineColour );
headPanel.graphics.beginFill( headerColour, 1 );
headPanel.graphics.drawRoundRect( stage.stageWidth / 2, 2, stage.stageWidth / 2 - 3, 25, 10 );
headPanel.graphics.endFill();
}
else
{
trace("headPanel not on screen");
}
public function removedHeader ( e : Event ):void {
stage.removeEventListener( Event.RESIZE, resizeHeader );
stage.removeEventListener( Event.REMOVED_FROM_STAGE, removedHeader );
headPanel.graphics.clear();
removeChild( headPanel );
}
}//End Class
}//End Package
Trace results from preLoader :
Trace results from Main :
As you can see, the preloader fires twice for the UINav, and three times for the Header, and in the main it fires the UINav once and the header twice.
Any clues please as this is driving mental!?
I understand the essence of why this would be but if I'm adding an object within another object why does it account for if being placed on stage at each level. If I add a toggle to the highest object added, after its been removed, when it re-adds the object to the stage it only fires the once!?
Firstly, is this normal? I've seen issues raised about similar examples of ADDED_TO_STAGE firing twice and tried all but nothing makes a difference, I've cleared and removed all eventListeners after they are initialised but nothing makes a difference.
Is there a way to stop this from happenening or can someone please shed some light on the best procedure to work with nested Movieclips!? Also, if this is regular, surely this is a major drawback from using an external preloader too?
Thanks in advance.
Resolved : (thanks to @ices_2)
For any others suffering, here's the ammended code to use ADDED_TO_STAGE with trace handlers to see the event being added and removed.
public function Site_UINav()
{
if ( this.stage ) initUINav();
else
this.addEventListener( Event.ADDED_TO_STAGE, initUINav );
this.addEventListener( Event.REMOVED_FROM_STAGE, removedUINav );
}
public function initUINav( event : Event = null ):void
{
trace( "UINav listerner present (a): " + this.hasEventListener( Event.ADDED_TO_STAGE ));
if(this.hasEventListener( Event.ADDED_TO_STAGE ))
{
//remove listener if it was added
this.removeEventListener( Event.ADDED_TO_STAGE, initUINav );
}
trace( "UINav listerner present (b): " + this.hasEventListener( Event.ADDED_TO_STAGE ));
}
Remove the REMOVE_FROM_STAGE event :
private function removedUINav ( event : Event ):void
{
stage.removeEventListener( Event.RESIZE, resizeUINav );
trace( "UINav listerner present (c): " + this.hasEventListener( Event.REMOVED_FROM_STAGE ));
if(hasEventListener( Event.REMOVED_FROM_STAGE ))
{
//remove listener if it was ever added
this.removeEventListener( Event.REMOVED_FROM_STAGE, removedUINav );
}
trace( "UINav listerner present (d): " + this.hasEventListener( Event.REMOVED_FROM_STAGE ));
}
Thanks again, so many examples online of people suffering ADDED_TO_STAGE duplicates instances and no real explanation as to how to use them correctly.
Everyday's a school day!
Upvotes: 1
Views: 238
Reputation: 357
You are not clearing event listeners because they bind to this, and not the stage. You shold remove event listener from class like this:
public class Preloader extends MovieClip
{
public function Preloader()
{
if (stage)
this.init();
else
this.addEventListener(Event.ADDED_TO_STAGE, init);
}
private function added(event:Event):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, init);
trace("added");
}
}
This code will trace "added" in console only one time.
Upvotes: 1