pass data to child swf after swf loading completed - actionscript-3

I am loading one swf file inside a main swf by using swfloader and i want to pass the parameters to the loaded swf. How can i get the loaded child reference to pass data.
My sample code is as follows
TestFile1.mxml
public var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, myFun);
loader.load(new URLRequest("/view/flex/TestFile2.swf"), new LoaderContext(false, ApplicationDomain.currentDomain));
viewId.addChild(loader);
public function myFun(event:Event):void{
Alert.show("loader.content-"+loader.content); // here alert coming like this [object_TestFile2_mx_managers_SystemManager]
var testfile2:TestFile2 = loader.content as TestFile2; // here testfile2 is null
testfile2.param1 = "val1";
}

There are 2 options.
If you just need simple startup values, you can pass arguments in the loader string and have TestFile2 grab them on start.
new URLRequest("/view/flex/TestFile2.swf?param1=val1")
If you need to interact with the child, you need to grab a reference to it after the application complete event. Event.COMPLETE only fires when the loader is loaded. In the Event.COMPLETE event, add an event to fire when the content is ready.
public function myFun(event:Event):void{
Alert.show("loader.content-"+loader.content); // here alert coming like this [object_TestFile2_mx_managers_SystemManager]
loader.content.addEventListener(FlexEvent.APPLICATION_COMPLETE, appCreationComplete);
}
private function appCreationComplete(event:FlexEvent):void
{
var testfile2:TestFile2 = loader.content["application"] as TestFile2; // here testfile2 is not null
testfile2.param1 = "val1";
}

Related

AS3 Air Desktop - Dispatch Custom Event from SWF in ApplicationStorageDirectory

I have a series of Air Desktop games that I created. Before the game can be played, the user must first log in. In order to streamline things, I created the login system in a separate project and saved it as a swf file called, "dashboard.swf". When the game is opened, it loads dashboard.swf and displays the login screen. In addition to the login functionality, dashboard.swf also handles a bunch of other stuff like common settings amongst the games.
I didn't want to recompile each game every time I made a change to the dashboard.swf. So, I have it download from a server. I was originally downloading, saving, and loading dashboard.swf in the ApplicationDirectory and it worked fine on Macs. After testing on Window 10 and doing some research, I found that ApplicationDirectory for non-OSX machines is read-only.
So, I changed the location of the dashboard.swf to the ApplicationStorageDirectory. When I run it on my Mac, the swf loads just fine, but the first custom event that gets dispatched throws and error:
TypeError: Error #1034: Type Coercion failed: cannot convert com.thisapp.event::CustomEvent#12786a9fed31 to com.thisapp.event.CustomEvent
Both CustomEvent.as files are identical. It fires just fine when dashboard.swf is saved to and loaded from the ApplicationDirectory on the Mac. Once I move it to ApplicationStorageDirectory, I get this error. So I know it's not an issue with the actual custom dispatcher. Bubbling is true and so in Cancellable.
What would be causing the Type Coercion failure in this situation?
Here's my custom dispatcher:
public class CustomEvent extends Event {
public static const GOT_RESULT: String = "gotResult";
public var result: Object;
public function CustomEvent(type: String, result: Object = null, bubbles: Boolean = false, cancelable: Boolean = false) {
// constructor code
super(type, bubbles, cancelable);
this.result = result;
}
public override function clone(): Event {
return new CustomEvent(type, result, bubbles, cancelable);
}
}
From my dashboard.swf:
dispatchEvent(new CustomEvent(CustomEvent.GOT_RESULT, null,true,true));
In my Main class for the desktop app:
var dashboardURL:String = File.applicationStorageDirectory.url +"dashboard.swf";
var myContext:LoaderContext = new LoaderContext();
myContext.applicationDomain = ApplicationDomain.currentDomain;
var urlReq:URLRequest = new URLRequest(dashboardURL);
var ldr:Loader = new Loader();
ldr.load(urlReq, myContext);
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,loadit);
function loadit(e:Event){
dashboard = e.target.content as MovieClip;
addChild(dashboard);
dashboard.addEventListener(CustomEvent.GOT_RESULT, runLogin);
}
ANSWER
See #BadFeelingAboutThis's answer below to understand why the 1034 error is happening. Here's how I fixed it:
First - Download the swf from the server (I'm using the GreenSock's LoaderMax):
private function dowloadDashboard(){
var url:String = "https://path/to/your/swf/on/the/server.swf";
var queue:LoaderMax = new LoaderMax({name:"mainQueue",onComplete:completeHandler});
//Note: the format is set to "binary"
queue.append( new DataLoader(url, {name:"mySwf",format:"binary", estimatedBytes:3000}) );
queue.load();
function completeHandler(event:LoaderEvent):void {
//Note: "mySwf" is the name I gave to the DataLoader above.
var b:ByteArray = LoaderMax.getContent("mySwf");
//loadDashboard() is the next function and I'm passing the ByteArray to it.
loadDashboard(b);
}
}
Next - Load the swf with the proper context using the ByteArray:
private function loadDashboard(b:ByteArray) {
var myContext:LoaderContext = new LoaderContext();
myContext.allowLoadBytesCodeExecution = true;
myContext.allowCodeImport = true;
myContext.applicationDomain = ApplicationDomain.currentDomain;
var ldr:Loader = new Loader();
ldr.loadBytes(b,myContext);
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,loadDone);
}
Last - Add your swf to the stage:
function loadit(e:Event){
dashboard = e.target.content as MovieClip;
addChild(dashboard);
}
I hope that helps somebody! Remember, in my situation, I have a Desktop Air app that is downloading and loading a swf file that lives on a server.
This error typically means that you have the same Class coming into your root application from different sources.
In your case CustomEvent class must exist in both the host SWF file as well as your loaded in SWF file.
Because your loaded SWF is not in the same application domain as the host SWF, flash/AIR will not see overlapping classes as the same class. So you loaded in SWF CustomEvent is now seen as com.thisapp.event::CustomEvent#12786a9fed31 which (though exactly the same) is seen as a totally different class than com.thisapp.event:CustomEvent. Since your code references the latter, anytime a CustomEvent from the host tries to get stuffed in an object reference typed :CustomEvent it will throw a coercion error because they aren't actually same class.
Usually, the remedy for this problem is to specify the context for the loaded SWF so it integrates the loaded Classes into it's own domain. This should overwrite the host CustomEvent with the loaded SWF's CustomEvent
var ldr:Loader = new Loader();
//The second parameter for load takes a LoaderContext
ldr.load(new URLRequest(File.applicationStorageDirectory.url +"dashboard.swf"), new LoaderContext(false, ApplicationDomain.currentDomain));
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,loadit);
function loadit(e:Event){
dashboard = e.target.content as MovieClip;
addChild(dashboard);
dashboard.addEventListener(CustomEvent.GOT_RESULT, runLogin);
}
Read more about the loader context here and here

Unloading swf file through button click

So I'd like to set this up to where you click on a button it loads a new scene and unloads the previous scene.
This is what I have so far.
staart.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler);
function fl_MouseClickHandler(event:MouseEvent):void
{
function loadSWF(swfURL){
var myLoader:Loader = new Loader();
var mySWF:URLRequest = new URLRequest(swfURL);
myLoader.contentLoaderInfo.addEventListener
(Event.COMPLETE,onCompleteHandler);
myLoader.contentLoaderInfo.addEventListener
(ProgressEvent.PROGRESS,onProgressHandler);
myLoader.load(mySWF);
}
function onCompleteHandler(loadEvent:Event){
addChild(loadEvent.currentTarget.content);
loadEvent.currentTarget.content.gotoAndStop(swfFrame);
}
function onProgressHandler(myProgress:ProgressEvent){
var percent:Number =
Math.round(myProgress.bytesLoaded/myProgress.bytesTotal*100);
trace(percent+"% loaded");
}
}
var swfFrame:Number= 1;
loadSWF("home.swf");
}
Is it possible to unload a specific swf file or previous swf file through a newly loaded swf file?
You should create a variable for your swf.
Add this to your code :
var mc:MovieClip = new MovieClip();
// Adds the movie clip at initialization.
addChild(mc);
and modify your onCompleteHandler method like this :
function onCompleteHandler(loadEvent:Event){
// Changes the content of your movie clip.
mc = loadEvent.currentTarget.content;
mc.gotoAndStop(swfFrame);
}
shawn gave you the right answer but there are 2 other problems in your code:
There's a typo in element staart and a potential memory leak because you add event listeners without removing them. You should add the following two lines in onCompleteListener function:
loadEvent.currentTarget.removeEventListeners(Event.COMPLETE,onCompleteHandler)
loadEvent.currentTarget.removeEventListeners(ProgressEvent.PROGRESS,onProgressHandler)
If you don't remove the listeners, the garbage collector will be unable to free the memory of every loader you create on each click

How to loop SWF file loaded with Loader?

I want to loop a swf file that has been loaded with via the Loader class in AS3.
My code looks as following:
public class MyLoader extends MovieClip {
public function MyLoader() {
var myLoader:Loader = new Loader();
var url:URLRequest = new URLRequest("external-movie.swf");
myLoader.load(url);
myLoader.contentLoaderInfo.addEventListener("complete", function() {
});
addChild(myLoader);
}
}
From what I understand the Loader has no event for when the embedded movie is finished? Is there a way to figure that out? It must not be a AS3 implementation. I just want a movie that has been exported from Indesign to run in a loop. Thanks in advance
Especially when you have little experience programming you should avoid dirty shortcuts as they'll only get you a lot of trouble. So avoid anonymous function and avoid using string in place of static event variables.
This being said, if your loaded movie has its own timeline then it will be converted into a MovieClip. Also that movie is not embedded but loaded and that's a big difference.
Keep a reference of that movie and the loader:
private var theLoadedMovie:MovieClip;
private var myLoader:Loader;
Listen for the INIT event instead of the COMPLETE event (movies with timeline start to play when their first frame is loaded "INIT", the COMPLETE event fires when the whole movie is loaded).
myLoader = new Loader();
var url:URLRequest = new URLRequest("external-movie.swf");
myLoader.load(url);
myLoader.contentLoaderInfo.addEventListener(Event.INIT, handleInit);
In your handleInit method keep a reference of that movie:
theLoadedMovie = myLoader.content as MovieClip;
addChild(theLoadedMovie);
theLoadedMovie.addEventListener(Event.ENTERFRAME, handleEnterFrame);
in your handleEnterFrame method check the movie progress to know when it has ended:
if(theLoadedMovie.currentFrame == theLoadedMovie.totalFrames)
{
//movie has reached then end
}

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.

Loading another swf file using AS3

I'm trying to load in another swf on a button click using Aaction Script 3.
The problem I'm having is that it just seems to load and mix the movies together. Is is possible to load and replace on stage the newly loaded swf similar to how you could do this in AS2 using loadMovieNum()
This is what I have so far:
//Add event listener for button click
backButton.addEventListener(MouseEvent.CLICK, backButtonClick);
//Create a function for the button click
function backButtonClick(ev:MouseEvent):void
{
var request:URLRequest = new URLRequest("2.swf");
var loader:Loader = new Loader()
loader.load(request);
addChild(loader);
}
Many thanks
Use the loader like this:
//Add event listener for button click
var singleLoader:Loader = new Loader();
backButton.addEventListener(MouseEvent.CLICK, backButtonClick);
//Create a function for the button click
function backButtonClick(ev:MouseEvent):void
{
var request:URLRequest = new URLRequest("2.swf");
singleLoader.load(request);
addChild(loader);
}
What you're doing is you're creating a new Loader every single time for every new SWF you're loading. Just use a single loader and each time you load content on it, it should replace the existing content. If not, adjust the code like so:
function backButtonClick(ev:MouseEvent):void
{
var request:URLRequest = new URLRequest("2.swf");
singleLoader.unloadAndStop(true);
singleLoader.load(request);
addChild(loader);
}
See the documentation for more: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Loader.html
Update
If you want to clear everything off the stage when you do this, see the following question & answer My Actionscript 3.0 Stage will not clear.