AS3 objects (buttons) from library not accessible from within certain functions - actionscript-3

I'm working on a simple image processor in AS3 and as usual I almost had it finished when an annoying little problem appeared. I want to open an image using a dialog box, and once the image is open I want the "selectBtn" (which is in my Library) to disappear. However when I try the code below I get a: "Error #1009: Cannot access a property or method of a null object reference". I'm sure it's something simple but I just can't figure it out!
// declare variables
var image:Bitmap;
var loader:Loader = new Loader();
var fileRef:FileReference= new FileReference();
selectBtn.addEventListener(MouseEvent.CLICK, openImage);
function openImage(event:MouseEvent):void {
fileRef.browse([new FileFilter("Images", "*.jpg;*.gif;*.png")]);
fileRef.addEventListener(Event.SELECT, onFileSelected);
}
function onFileSelected(e:Event):void {
fileRef.addEventListener(Event.COMPLETE, onFileLoaded);
fileRef.load();
}
function onFileLoaded(e:Event):void {
loader.loadBytes(e.target.data);
image = Bitmap(loader.content);
selectBtn.visible = false;
}

What Todd says is accurate: where is "selectBtn" defined? Is it on a stage, or nested within some movieclip instance?
Assuming the button exists on the stage, and the code runs in the same frame as the button exists, you could try this.stage.selectBtn.visible = false;
Otherwise, trace that you have selectBtn as a reference. Or you could declare a variable to reference it. i.e.:
var selectBtnRef:Button = this.stage.selectBtn;

Related

Actionscript 3: How can I change the name property of content returned by Loader.load()? Error 1074

I have a Scaleform movie that I want to serve as the container for my game's user interface. I want it to be able to load and unload other swf files that will serve as different HUDs and menus. And when I load a swf, I need Actionscript to register the name of the DisplayObject, so the game will know which "view" (i.e., HUD, pause menu, shop menu, etc.) just loaded.
I am able to load other swfs using Loader.load(), but for some reason I can't change their names. I keep getting error 1074.
[Edit: Adding more info on the error. "Error #1074: Illegal write to read-only property." Apparently I'm trying to write to a read-only property. So how do I make that property not-read-only? name isn't read-only in any other UIComponents I'm loading.]
public function loadView(viewName:String, movieFileName:String):void
{
var loader:Loader = new Loader();
var url:URLRequest = new URLRequest(movieFileName);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
loader.name = viewName;
loader.load(url);
}
private function loaderComplete(e:Event):void
{
var loader:Loader = e.currentTarget.loader as Loader;
var content:DisplayObject = LoaderInfo(e.target).content; // This returns the content I'm looking for, but I always get error 1074 if I try changing its name
// var content:DisplayObject = loader.getChildAt(0); // This also returns the content I'm looking for, but it also gives me error 1074 if I try changing its name
// content.name = loader.name; // This line always gives me error 1074
// var newView:View = View(content); // Even if I try casting the content as a custom .as class...
// newView.setName(loader.name); // public function setName(newName:String):void { this.name = newName; } // ...I still get error 1074
addChild(content);
}
Am I just not allowed to change the name property of swf movies that get returned? Can I set the name in the document class of the swf? I tried that too, but no matter where I change the name inside the document class (their class extends scaleform.clik.core.UIComponent, and I try setting the name in the constructor and in configUI), it always seems to get overwritten when I addChild().
[And another edit. Apparently there is some confusion over the "name" property. Here's how it works...]
I start off with this code. I just put it in frame 1 of my movie.
import TestUIComponent;
var testUIComponent:TestUIComponent = new TestUIComponent();
testUIComponent.name = "Something something";
trace("This is the testUIComponent's name: " + testUIComponent.name);
addChild(testUIComponent);
This is the class TestUIComponent:
package {
import scaleform.clik.core.UIComponent;
public class TestUIComponent extends UIComponent {
public function TestUIComponent() {
}
override protected function configUI():void {
super.configUI();
enableInitCallback = true;
}
}
}
Nothing fancy there. It's just an Actionscript 3 scaleform.clik.core.UIComponent (need to specify that because I think there are at least 3 different UIComponents in different packages). enableInitCallback is a property that used to be visible in Flash's properties panel, but now in AS 3, it seems you can only change it in code.
So I run that code, and this is what I see:
This is the testUIComponent's name: Something something
CLIK Load: root.Something something
If I comment out the line
// testUIComponent.name = "Something something";
and then run the code, this is what I see:
This is the testUIComponent's name: instance1
CLIK Load: root.instance1
Going back to my original problem, the text that comes after "CLIK Load:" is the name that is getting sent from the UI to the game. I need that name to be something meaningful so the game knows what just got loaded. The swf files I am trying to load have Document Classes that are children of scaleform.clik.core.UIComponent, so I thought their name properties would work the same way as the TestUIComponent above. Apparently it doesn't. And as you can see all the way back up at the top, I even cast the loader.content as a View (which is a child of UIComponent), and I still can't change the name.
This is what I meant in the comments. Try something like this:
//... where you declare your variables, make them public to use in other functions...
public var myString = "";
//... later where you declare functions...
public function loadView(viewName:String, movieFileName:String):void
{
var loader:Loader = new Loader();
var url:URLRequest = new URLRequest(movieFileName);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
//loader.name = viewName;
myString = viewName; //# 1) update String here to re-access in next function...
loader.load(url);
}
private function loaderComplete(e:Event):void
{
var content:DisplayObject = LoaderInfo(e.target).content; // This returns the content I'm looking for, but I always get error 1074 if I try changing its name
// content.name = loader.name; // This line always gives me error 1074
content.name = myString; //# 2) set content name to whatever myString holds (ie the viewName)...
addChild(content);
}

Go to specific frame after external swf has been loaded AS3

I have been looking for solutions around here but I can't seem to get it right.
Basically I am trying to load an external swf after clicking on a 'Next' button and it will automatically go to a specific frame eg. frame 8 instead of frame 1.
At first I've got an error of using of using MovieClip function in a Loader and such.
Here's my code
nextBtn.addEventListener(MouseEvent.CLICK, fl_ClickToLoadUnloadSWF_1);
var fl_Loader1:Loader;
var fl_ToLoad1:Boolean = true;
function fl_ClickToLoadUnloadSWF_1(event:MouseEvent):void
{
if(fl_ToLoad1)
{
fl_Loader1 = new Loader();
fl_Loader1.load(new URLRequest("projectnowd.swf"));
addChild(fl_Loader1);
var fl_Loader1:MovieClip = event.target.content as MovieClip;
fl_Loader1.gotoAndStop(8);
}
else
{
fl_Loader1.unload();
removeChild(fl_Loader1);
fl_Loader1 = null;
}
fl_ToLoad1 = !fl_ToLoad1;
}
You can access content of loaded swf only after event. Complete was dispatched while loading swf file on to the stage.
Define event handler method to start from 8 th frame
function loaderCompleteHandler(evt:Event):void {
var loadedMovie:MovieClipp = evt.currentTarget.content as MovieClip;
loadedMovie.gotoAndStop(8);
}
Replace if block with below lines of code
if(fl_ToLoad1)
{
fl_Loader1 = new Loader();
fl_Loader1.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler);
fl_Loader1.load(new URLRequest("projectnowd.swf"));
addChild(fl_Loader1);
}
Happy coding :)

as3 error: access of possibaly undefind property through a reference with static type flash.display:DisplayObject

I have this as3 project, and in frame one of the timeline I tried to load a swf movie named "menu" and in this loaded movie I have an instance of a button named "button1", and I want to add a new EventListener to this "button1". my code is here:
var theLoader:Loader = new Loader();
var address:URLRequest = new URLRequest("menu.swf");
theLoader.load(address);
theLoader.contentLoaderInfo.addEventListener(Event.COMPLETE , swfDidLoad);
function swfDidLoad(evt:Event){
if(theLoader.content){
addChild(theLoader);
var button:SimpleButton = theLoader.content.button1;
button.addEventListener(MouseEvent.CLICK, handler1);
}
}
function handler1 (event:MouseEvent):void
{
removeChild(theLoader);
gotoAndStop(10);
};
but I get this undefind property error. what should I do? Am i doing this right at all?
The reason you are getting that error is because you are trying to access button1 on theLoader.content which is a non-dynamic DisplayObject (this means that only explicitly defined properties/methods are valid). You must first cast it to a MovieClip (which is dynamic).
You should change that line to:
var button:SimpleButton = MovieClip(theLoader.content).button1;

AS3 Retrieving a file from FZip

I am currently coding a game and I am storing all external files in a zip file to save space.
I am trying to use Fzip to load an image out of the Zip file and display it on stage but I am having no luck.
FZip Site - http://codeazur.com.br/lab/fzip/
Example 1 Site - http://www.tuicool.com/articles/7VfQr2
I have got the zip file to load and return me the number of files inside it but I cannot figure out how to retrieve an image called "test.png".
import deng.fzip.FZip;
import deng.fzip.FZipFile;
import deng.fzip.FZipLibrary;
import flash.display.*;
var zip:FZip = new FZip();
var loaderzippy:Loader = new Loader();
function unzipObb():void {
zip.load(new URLRequest("file://"+File.applicationStorageDirectory.nativePath+"/cake2.zip"​));
zip.addEventListener(Event.OPEN, onOpen);
zip.addEventListener(Event.COMPLETE, dosomething); }
function dosomething(evt:Event):void {
trace("dosomething");
var img_file:FZipFile = zip.getFileByName("test.png");
var loaderzip:Loader = new Loader();
loaderzip.loadBytes(img_file.content);
var image:Bitmap = Bitmap(loaderzip.content);
addChild(image); }
I just get returned #2007: Parameter child must be non-null.
Any help would be great. Thanks.
When you load the PNG bytes using loaderzip.loadBytes(), you need an event listener to check when it's done loading. The documentation itself states:
The loadBytes() method is asynchronous. You must wait for the "init" event before accessing the properties of a loaded object.
Because you're trying to access the code directly after you called loadBytes(), at which point it hasn't actually loaded anything, you're getting a null bitmap.
Although you can access the data once the "init" event has been dispatched, it's best to wait for the "complete" event, since you want your image to be done loading (rather than halfway done).
I've tweaked your code to something that should work:
function dosomething(evt:Event):void {
trace("dosomething");
var img_file:FZipFile = zip.getFileByName("test.png");
var loaderzip:Loader = new Loader();
loaderzip.contentLoaderInfo.addEventListener(Event.COMPLETE, getImage);
loaderzip.loadBytes(img_file.content);
}
function getImage(e:Event):void {
var loaderInfo:LoaderInfo = e.currentTarget as LoaderInfo;
var image:Bitmap = Bitmap(loaderInfo.content);
addChild(image);
}
(I haven't tested this myself but it's just to give you the general idea anyway.)
Note that you should add the event listener to loaderzip.contentLoaderInfo, not just loaderzip. That's what actually dispatches the event and it also contains the loaded content.

How Do I Reference a Dynamically Instantiated Object in AS3? (Added a Moviclip to the Stage)

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