FLex : unload swf file in SWFLoader - apache-flex

In Flex 3 I have a SWFLoader:
<mx:SWFLoader id="player" source="http://youtube.com/v/..." />
and after some time I invoke player.unloadAndStop(). And I always get this error:
ReferenceError: Error #1056: Cannot create property __tweenLite_mc on _swftest_mx_managers_SystemManager.
What does it mean and how to avoid this?
UPD: AIR 2 doesn't have this problem

Maybe try the Loader class? I'm not sure if it will help but I do all my loading via ActionScript. Generally speaking, I do "heavyWeight" programming/logic/cotrol stuff in ActionScript and leave Flex for more simplistic layout code. That is, flex puts things in place and actionscript controls it all. When loading clips in our Flex 3 project, I have control code along the lines of:
import flash.display.Loader;
private var loader:Loader;
public function init() {
loader = new Loader();
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, loadFailed);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadCompleted);
}
with calls to things like:
//here, pop returns a string like "/path/to/movie.swf"
loader.load(new URLRequest(clipsToPlay.pop()));
...
loader.unload();
contained in functions like:
private function loadNextClip():void {
if(clipsToPlay.length == 0) {
dispatchEvent(new PlayBackCompleteEvent(PlaybackCompleteEvent.ALL));
return;
}
loader.load(new URLRequest(clipsToPlay.pop()));
}
private function loadCompleted(event:Event):void {
currentClip = event.target.content as MovieClip;
loader.unload();
displayClip();
}
private function displayClip():void {
applyEffects();
currentClip.addEventListener(Event.ENTER_FRAME, monitorForCompletion);
addChild(currentClip);
}
I'm not sure if Loader can be used instead of SWFLoader but if so I hope that helps you or someone else, in some way...
EDIT:
I just looked it up and mx.controls.SWFLoader and flash.display.Loader have very similar functionality. I'd try using Loader, as prescribed above, and see if it fixes the problem. You could probably initialize the loader via MXML, too, but I wouldn't recommend it since it's not a visual component, I think it's better to let MXML handle visual things while ActionScript handles logical things.

Related

create own frames animation and play in movieclip

how can i create own frames animation and play in movieclip or any movieclip extends.. i have this code but is wrong - i'm flash builder beginner so i don't know how work it..i can do it in MovieClip
<?xml version="1.0" encoding="utf-8"?>
public var mc:MovieClip;
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
var comp:UIComponent = new UIComponent();
this.addElement(comp);
mc = new MovieClip();
for (var i:int =0; i<100; i++)
{
var rect:Sprite = new Sprite();
rect.graphics.beginFill(0x330000);
rect.graphics.drawCircle(0, 0, 20);
rect.graphics.endFill();
rect.x=30 + (i%40)*5;
rect.y=100;
mc.addChild(rect);
}
comp.addChild(mc);
}
protected function button1_clickHandler(event:MouseEvent):void
{
mc.play();
}
]]>
</fx:Script>
<s:Button click="button1_clickHandler(event)"/>
thanks for help
Sadly there is no way to create MovieClip animations at runtime, they can only be created using Flash Authoring (or possibly other tools that can export to swf).
Your options are to either create a bunch of Sprite or possibly Shape and add/remove these from the display list as you progress throught the frames. Another option, if your graphics are simpler, you can generate them on the fly for each frame.
I think we'd need a bit more information about the type of animation you're hoping to create.
Depending on what it is, it could be very possible in theory. You'd be creating a separate class that extends MovieClip and instantiate that in your 'for loop'. That class could have all sorts of animation instructions and logic. Extending 'MovieClip' isn't the only option, but it does enable you to use Event.ENTER_FRAME where with a Sprite you'd need to set up an internal Timer or use a public 'update' or 'draw' method that can be called from your main code.
There are also 'Motion' classes that allow you to load XML animation instructions that you have a fair amount of control with. Look up fl.motion.Animator.
What are you trying to do? Welcome to ActionScript!

Error in using "removechild"

Below is my code, and the question is explained after it.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:cal="cal.*"
layout="absolute"
applicationComplete="init()"
xmlns:geometry="com.degrafa.geometry.*"
xmlns:degrafa="com.degrafa.*"
xmlns:paint="com.degrafa.paint.*"
xmlns:containers="flexlib.containers.*"
xmlns:flexlib_controls="flexlib.controls.*"
xmlns:mdi_containers="flexlib.mdi.containers.*"
xmlns:auto="com.hillelcoren.components.*"
xmlns:local="*"
xmlns:components="CollapsibleAccordion.*"
modalTransparency="0.8"
modalTransparencyColor="0x000000"
backgroundSize="100%">
<mx:Script>
<![CDATA[
import c7.views.components.PhotoViewer.PhotoViewer;
import c7.config.ServerConfig;
import mx.core.Application;
import mx.containers.*;
import c7.models.GlobalModel;
private var pv_slideshow:PhotoViewer = null;
private function toggleFullScreen():void
{
if(stage.displayState == StageDisplayState.NORMAL)
{
this.pv_slideshow = new PhotoViewer;
Application.application.addChild(this.pv_slideshow); //added as top-most component to application itself
//set new sizes & go full-screen
this.pv_slideshow.x = 0;
this.pv_slideshow.y = 0;
this.pv_slideshow.width = stage.fullScreenWidth;
this.pv_slideshow.height = stage.fullScreenHeight;
try
{
stage.displayState = StageDisplayState.FULL_SCREEN;
}
catch(err:Error)
{
Alert.show(err.toString());
}
stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenEventHandler, false, 0, true); //intentionally weak referenced
//refresh the display sizes & display list
invalidateSize();
invalidateDisplayList();
}
/*else
stage.displayState = StageDisplayState.NORMAL;*/
}
private function fullScreenEventHandler(event:FullScreenEvent):void
{
if (event.fullScreen) //nothing to do in case when switching to full-screen
return;
//Alert.show(pv_slideshow.width.toString());
//application.removeChild(this.pv_slideshow);
Application.application.removeChild(pv_slideshow); //remove the full-screen container
this.pv_slideshow = null; //reset
//refresh the display sizes & display list
invalidateSize();
invalidateDisplayList();
}
The toggleFullScreen is fired on the click of a button... and it working absolutely fine. But the issue is in "exit" . When I click escape key fullScreenEventHandler is fired and it should remove the pv_slideshow.
This is where I get a null object reference error on the line:
Application.application.removeChild(pv_slideshow); //remove the full-screen container
I have tried using this.pv_slideshow and other such things.
Plz help me figure it out. what am i doing wrong and how should I make it work.
This is exact error message I get:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.core::Container/http://www.adobe.com/2006/flex/mx/internal::removingChild()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:3315]
at mx.core::Container/removeChild()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2263]
at index_cloud/fullScreenEventHandler()[C:\development\flex_src\index_cloud.mxml:1661]
I wouldn't use Application.application either.
Please check first pv_slideshow really exists, you can get it's parent ( if has one ) and remove it later.
get the parent
pv_slideshow.parent
remove it from the parent_item
parent_item.removeChild( pv_slideshow )
Make sure also the version of Flex you are using, you may need to remove it with removeElement.
The intended architectural use of Application.application is not to use it as a uiComponent or displayObject, or whatever. If you're building a library project that is doing some calculations based on the application properties, or the application's systemManager, or you need access to the outter application from a loaded module, then you have good reason to use App.app.
You example is not one of those cases. Your best bet is to add your component to 'this' (as long as you're not going to use a "view" container), and do a this.removeChild. That should solve a good chunk of your issues.
Best of luck,
Jeremy

Flex: Get self SWF file name?

Is there a way I can programmatically determine the filename of the .swf my class is running in?
Thanks!
Stage has a loaderInfo property, which contains a url property that has the information you're looking for. You can get the stage property from any DisplayObject in Flex.
trace(stage.loaderInfo.url);
Just a helpful note: If you load one SWF into another, the loaded (inner) SWF will return an erroneous result if you use loaderInfo.url to try to get the filename. For instance, something like:
Path/To/Outer.swf/[[DYNAMIC]]/1
Instead of:
Path/To/Inner.swf
Beware!
That said, here is the code I use to get the current SWF name:
function SWFName(symbol:DisplayObject):String
{
var swfName:String;
swfName = symbol.loaderInfo.url;
swfName = swfName.slice(swfName.lastIndexOf("/") + 1); // Extract the filename from the url
swfName = swfName.slice(0, -4); // Remove the ".swf" file extension
swfName = new URLVariables("path=" + swfName).path; // this is a hack to decode URL-encoded values
return swfName;
}
Not from within flash, afaik. What do you need it for? There might be a better way to do it.
You can use loaderInfo.loaderURL to get the full path and name of you swf
Example of a class:
public class Main extends Sprite {
private function init():void {
removeEventListener(Event.COMPLETE, init);
var myUrl:String=loaderInfo.loaderURL;
var tmp:Array=myUrl.split("/");
var myName:String=tmp[tmp.length-1].split(".swf")[0];
}
public function Main() {
super();
if (stage)
init();
else
addEventListener(Event.COMPLETE, init, false, 0, true);
}
}
Things have changed a bit in more recent versions so I'll give an answer for Adobe Flash Builder 4.6 (geared towards Flash in browser, but you get the idea).
<s:Application ... applicationComplete="alertSwfUrl()">
<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;
private function alertSwfUrl():void {
var a:LoaderInfo = FlexGlobals.topLevelApplication.stage.loaderInfo;
ExternalInterface.call('alert', a.url);
}
]]>
</fx:Script>
</s:Application
Check out the LoaderInfo docs to figure out how to use the loaderInfo object associated with the stage.

Giving Flex MXML views their dependencies

I'm used to building applications using pure AS3. I always pass dependencies into the constructor of classes I make, but this method seems to not work out well for Flex MXML views.
It seems like I should define setters on the MXML class, which map to attributes in the tag/class instantiation. But using this method I cannot specify which properties are required and in what order I expect them etc.
What is the preferred method to give a Flex view it's dependencies?
A pattern I've used a couple times was to define a public init() method in the MXML which takes the argument that would normally have gone in the constructor. Then, whatever instantiates that MXML component is responsible for calling init() before using it.
Another way would be to create setters for the properties like you mentioned. In those setters store the values that are passed, then call invalidateProperties(). Then override the commitProperties() method in the MXML, and the first time that's called do your initialization (and maybe throw an exception if the needed properties weren't provided). As long as the user of your class sets all the properties before adding the component to the display list then it will work fine (I don't believe commitProperties() is called until after a component is added to the display list, either by being declared in MXML or by passing it to an addChild() call).
I haven't ever tried that second method (only just thought of it now), but it should work.
You can't force people to use parameters in the constructor, but you can force then to set properties before adding the item to the stage.
How's this:
<mx:HBox
added="{checkProps()}">
<mx:Script>
<![CDATA[
public var prop1:String;
public var prop2:String;
private function checkProps():void
{
if( !( prop1 && prop2 ) )
{
throw new Error( "Prop1 and prop2 must be set before "+
"adding this to the stage" );
}
}
]]>
</mx:Script>
</mx:HBox>
Realistically, if you're interested in forcing people to do something before adding it to the display list, then you're going to have to do something like this anyway.
There are a few things in Flex that you can override or listen to that are really important.
FlexEvent.CREATION_COMPLETE - set an eventListener for this (I usually do it in the constructor but you could do it in MXML as creationComplete attribute) and it acts like your constructor. Use getters and setters to pass through references to your dependencies as MXML attributes and store them locally then inside this handler you will apply them.
override protected function createChildren - this is called when it is time to add display list items to the component. You shouldn't do that during the constructor or creationComplete handlers. It is always tempting to addChild outside of this function but Adobe best practice is only to do so directly in this function.
override protected function updateDisplayList - this is where your drawing logic should happen (if there is any) or positioning/alpha/rotation/etc of children. This will get called if a CSS property changes, a child changes size or position or anything else that the Flex framework thinks may cause you to want to redraw the screen. You can force an updateDisplayList to get called by calling invalidateDisplayList
override protected function commitProperties - this is called when the dataProvider for a class is changed. Any time data within the component means you want to update internal data structures this should be called. You can force this to be called using invalidateProperties.
FlexEvent.ADDED_TO_STAGE - If you need to know when the component is actually added to the stage you can listen for this. In practice I can't remember ever actually using it ...
Always remember to call the super equivalents -- forgetting to do so will often cause the component to fail to appear at all (this happens to me at least 4 or 5 times a project). Also be aware that if you first invalidateProperties and then commitProperties and then invalidateDisplayList and then updateDisplayList you may see some jerkyness ... that is, invalidateDisplayList as soon as you know you'll want a redraw to avoid delay.
Also don't get too invested in Flex 3 since Flex 4 is just around the corner and it is quite a bit different. I have a feeling that much of this will no longer apply in the new component framework (names Spark).
edit a typical class stub:
package
{
import mx.containers.Canvas;
import mx.events.FlexEvent;
public class TestComponent extends Canvas
{
public function TestComponent()
{
super();
addEventListener(FlexEvent.CREATION_COMPLETE, init);
}
// acts as constructor
private function init(event:FlexEvent):void
{
// might as well be clean
removeEventListener(FlexEvent.CREATION_COMPLETE, init);
// do init stuff here
}
override protected function createChildren():void
{
super.createChildren();
// do any addChilds here that are necessary
}
override protected function commitProperties():void
{
super.commitProperties();
// update internal state when data changes
}
override protected function updateDisplayList(w:Number, h:Number):void
{
super.updateDisplayList(w, h);
// do any drawing, positioning, rotation etc.
}
}
}

Passing flashvars-style parameters to a loaded SWF

I have a Flex 3 app (player v9) which loads a Flash SWF (AS3, also player v9) and needs to dynamically pass it a collection of parameters which are known at run-time. These are parameters that are normally passed via the flashvars element in an HTML page. The embedded movie accesses these parameters via the loaderInfo.parameters object.
I've tried using SWFLoader and Loader classes with no success in param-passing.
Relevant details:
It's a local program, and cannot rely on query string parameters.
I've mucked with setting loaderInfo.parameters["foo"] = "123" from the embedding code, but the parameter never seems to wind up in the embedded movie.
I cannot place extra parameter-passing machinery in the embedded movie(s), as they are created by third parties.
Passing this params in URL won't help, because they're taken using javascript code in the html-wrapper.
The 'flashVars' params are taken using the Application.application.parameters, so, you have to set these params manually in your case.
If you are using SWFLoader to load another app, you should create the object, that will represent the application loaded and apply all you need:
<mx:Script>
<![CDATA[
import mx.managers.SystemManager;
import mx.controls.Alert;
import mx.events.FlexEvent;
private var loadedApp:Application;
private function onLoadComplete(event:Event):void {
var smAppLoaded:SystemManager = SystemManager(event.target.content);
smAppLoaded.addEventListener(FlexEvent.APPLICATION_COMPLETE, onLoadedAppComplete);
}
private function onLoadedAppComplete(event:FlexEvent):void {
try {
loadedApp = Application(event.target.application);
if(!loadedApp) throw new Error();
loadedApp.parameters["param1"] = "value1";
} catch (e:Error) {
Alert.show("Failed to get application loaded.", "Error", Alert.OK);
}
}
private function onLoadError():void {
Alert.show("Failed to load an application.", "Error", Alert.OK);
}
]]>
</mx:Script>
<mx:SWFLoader
width="100%" height="100%"
source="./AppToLoad.swf"
complete="onLoadComplete(event)"
ioError="onLoadError()" securityError="onLoadError()" />
The reason is simple.
I've discovered this today.
In the component loaded via SWFloader has parentApplication or Aplication.application set to the top level application (this witch loads component via SWFLoader).
And the loaded component can see flashvars set to the top level application.
This is probably the cause that setting parameters in SWFLoader does not have any impact.
I've set proper flashvars on my toplevel application and they are also seen in the loaded one :-).
When embedding a SWF on a web page you can pass flashvars as parameters on the URL to the SWF, perhaps the same could work in your case? If the SWF is located at file:///some/path/to/a.swf try using file:///some/path/to/a.swf?hello=world&foo=bar. It might work.
Would have saved myself a lot of time today if I had found this answer first: AS3 Pass FlashVars to loaded swf.
Essentially: since Flash Player 10.2 it has been possible to pass flashvars along by setting them as parameters on the LoaderContext.

Resources