views:

441

answers:

3

This is something that has been bugging me since I took up AS3 a year ago.

Example. I make a class that extends a Movie Clip and call it "LoaderBar" all it is is some text that says "Loading" and below it another movie clip that is a plain rectangle that I call "lBar"

When I call a function to load my image I add the Loader to the stage as such..

function imageLoader(URL:String):void

{

     var loader:Loader = new Loader(new URLRequest(URL));
     loader.contentLoaderInfo.addEventListner(ProgressEvent.PROGRESS, progressHandler);

      var loadBar:Loader Bar = new LoaderBar();
      addChild(loadBar);
}


function progressHandler(e:Event):void

{

    var pcent:Number = e.getBytesLoaded / e.getBytesTotal;
    // HERE IS WHERE I'D LIKE TO MAKE DIRECT REFERENCE TO MY LOADBAR;
   loadBar.lBar.width = pcent*100;



}

Essentially I just want to tell the lBar in the loadBar Movie Clip to be the width of the percent *100. (so that when the clip is loaded the loader bar is 100 pixels wide).

My problem is this. When I add the loadBar to the stage inside of a function, I cannot make reference to it inside of another function without doing some hack making a global variable outside of my function like...

var loadBarClip:MovieClip;

and inside the load function assigning the loadBar to the loadBarclip as such

loadBarClip = loadBar.

I feel like this is redundant. Does anyone know of anyway of accessing my loadBar without making a reference variable?

+2  A: 

I don't see a major problem in having the variable declared outside of the imageLoader function. If you were writing this in a class instead of the timeline then it would just be a class member variable and there is nothing wrong with that. They exist for this very reason.

If your deadset wanting to keep the loadBar variable local then you could always do this:

in the imageLoader function:

var loadBar:Loader Bar = new LoaderBar();    
loadBar.name = "loadBar";  
addChild(loadBar);

in the progressHandler function:

getChildByName("loadBar");
Allan
Thank you! The reason I'm adding this to the stage inside a function is before this function I do a clean sweep of all the children buried in it's parent clip. I basically have a "scene" (hate that word) who's visibility is just clicked off, depending where someone is in the navigation. Inside the scene are a set of functions that produce it's content. One of them being a "cleanScene()" function that removes all of it's children so I'm not using up excess memory. The problem is once I clean my scene I'm also eliminating anything I'm not adding to the stage dynamically.
Jascha
+1  A: 

Since lBar (or loadBar for that matter) is an element that you need to manage at a class level, you should indeed make it a class member. There is nothing wrong with it ;)

Cay
I'm actually cheating when I'm saying class... I'm using the "Export for Actionscript" in the properties panel of the library. Although I'd love to do everything in textedit, I'm also a bit lazy.
Jascha
A MovieClip with code in its timeline is also a class for flash... the compiler generates a class with the name you declare in the "Class name" field, and the properties and functions you declare in any of its frames. Then, the "non-declarative" code itself is inserted to the class via addFrameScript... So you can actually treat your movieclips as classes, even if you don't create an external class file for them ;)
Cay
+2  A: 

If it's just for that handler, you could make the handler anonymous and keep in inside the current scope.

var loadBar = new LoaderBar();
var loader:Loader = new Loader(new URLRequest(URL));
loader.contentLoaderInfo.addEventListner(
    ProgressEvent.PROGRESS, function (e:Event):void {
      var pcent:Number = e.getBytesLoaded / e.getBytesTotal;
      loadBar.lBar.width = pcent*100; //Here you are making a direct reference.
    }
);

If you really want to encapsulate your scopes you could use closures:

returnFromEncapulatingClosure = function(){
    var loadBar = new LoaderBar();
    var loader:Loader = new Loader(new URLRequest(URL));
    return {
        loadBar: loadBar,
        loader: loader
    };
}();

That allows you to bundle together some references so they won't clobber other parts of code, and you could refer to it with:

returnFromEncapulatingClosure.loader.contentLoaderInfo.addEventListner(ProgressEvent.PROGRESS, progressHandler);
function progressHandler(e:Event):void {
  var pcent:Number = e.getBytesLoaded / e.getBytesTotal;
 returnFromEncapulatingClosure.loadBar.lBar.width = pcent*100;
}

As a footnote, when you extend the Movie Clip, add a method that sets the lBar.width. Something like:

loadbar.setLBarWidth = function (w:number) {
  this.lBar.width = w;
}
dlamblin
love it!! RE: The foot note, For some reason I've adapted a liking to controlling everything from the base. I feel I'm not digging through classes to see what's doing what to itself, rather starting from home and putting my controls on everything from the ground up. I don't always do that, and I guess that's not very OOP of me, but I am just getting started. Thanks again, awesome tips.
Jascha
oh man, this rules!! It worked great. In this way I can also get rid of the loader when I'm done loading by adding another handler for the Event.COMPLETE.You just changed the way I write my load event handlers for ever.
Jascha
I am very glad you like it. I think it's quite clean, and makes things readable and organized when using anonymous functions. For events, I only used named functions when they're getting reused. Also note that for the closure I mentioned, the `returnFromEncapsulatingClosure` should be named something that works for your context, and you could take out the named vars and put the `new` statements right into the returned object.
dlamblin