Flex: Get self SWF file name? - apache-flex

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.

Related

FLex : unload swf file in SWFLoader

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.

Is it possible to prevent a flex application from being resized at runtime?

From what I can gather, the resize property of a Flex application is set in the XML config file:
<!--Whether the user can resize the window. Optional. Default true.-->
<!--<resizable></resizable>-->
However, if I set this attribute to true, is there a way to turn this off dynamically at runtime? For example, my application has two view modes - mini and maxi. I would like to prevent the end user from being able to resize the application when in mini mode. I tried prevent the resize using the following code but it does not seem to work:
private function creationComplete():void {
this.systemManager.stage.addEventListener(Event.RESIZE, resizeListener);
}
private function resizeListener(evt:Event):void {
evt.preventDefault();
}
Any help would be greatly appreciated.
There is another way to do that without setting the descriptor file property.
Here is the code:
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" showGripper="false"
layout="vertical" showStatusBar="false"
applicationComplete="init()">
<mx:Script>
<![CDATA[
import mx.events.FlexNativeWindowBoundsEvent;
private function init():void
{
this.stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
nativeWindow.addEventListener(NativeWindowBoundsEvent.RESIZING, onAppResize);
}
private function onAppResize(e:NativeWindowBoundsEvent):void
{
e.preventDefault();
}
]]>
</mx:Script>
Hope this helps.
You'd need to create a new NativeWindow instance and reparent your application into that. When you create a new NativeWindow, you've got options you can set at Initialisation time, including resizable.
http://help.adobe.com/en_US/FlashPlatform//reference/actionscript/3/flash/display/NativeWindowInitOptions.html
According to manual, resizable is read-only property.
So it's probably not possible.
As this was already necro'd, and I was curious:
I was able to implement a switch from resizable to not with the following code:
private var maxMode:Boolean = true;
protected function switchMode():void
{
if (maxMode){
//I chose to freeze the app at current size
//You could also set the min/max to hard coded values
this.maxWidth = this.width;
this.minWidth = this.width;
this.maxHeight = this.height;
this.minHeight = this.height;
}
else {
//default values for WindowedApplication
this.maxWidth = 2880;
this.minWidth = 0;
this.maxHeight = 2880;
this.minHeight = 0;
}
maxMode= !maxMode
}
The user is however still shown the resize mouse icons on the edges of the app.
Try to add return:
evt.preventDefault();
return;

Unreachable, existing variable

I'm new at as3, maybe thats the reason why i don't understand, why the setInterval causes an error.
<mx:Script>
<![CDATA[
import flash.utils.setInterval;
import mx.controls.Alert;
[Bindable]
public var MyInt:int = 500;
setInterval(function():void{ ++MyInt; },1000);
]]>
</mx:Script>
I have a label where the value of MyInt gets visible, the bind works perfect, i've tested it several ways, and i i create a button it grows the number, but if i use the setInterval function i get an error: Access of undefined property myInt.
Why? What does cause this? Please explain it, so I can avoid errors like this. Thanks
I don't know much about Flex, but I think the problem is that this code:
setInterval(function():void{ ++MyInt; },1000);
Is run like if it was placed in a class definition, outside any function. That makes the code a static initializer. That is, it's run in a static context, which means it has no access to any instance, since no instance has yet been created when the code runs.
This seems to prove it:
public static var MyInt:int = 500;
setInterval(function():void { ++MyInt; trace(MyInt); },1000);
With static, the code works fine.
You probably don't want MyInt to be static, though. So you should put the setInterval call within an instance method. Assuming init is called from the mx:Application initialize callback, this should work fine:
[Bindable]
public var MyInt:int = 500;
private function init():void {
setInterval(function():void { ++MyInt; trace(MyInt); },1000);
}

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

Watching a bindable property

In my flex app I have a public bindable property.
I want it so that every time the value of that property changes, a function gets triggered.
I tried using ChangeWatchers, but it seems those only apply to built-in components like a text box change.
I would like to do that same behavior with a property that changes at runtime.
One option is to use BindingUtils.bindSetter (which incidentally returns a ChangeWatcher):
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="this_creationComplete()">
<mx:Script>
<![CDATA[
import mx.binding.utils.BindingUtils;
import mx.binding.utils.ChangeWatcher;
[Bindable]
public var myValue:int = 0;
private function this_creationComplete():void
{
var cw:ChangeWatcher = BindingUtils.bindSetter(myValueChanged, this, "myValue");
}
private function setValue():void
{
myValue = getTimer();
}
private function myValueChanged(o:Object):void
{
trace("myValue: " + myValue.toString());
// You can also use o.toString() -- the new value will be passed into the function
}
]]>
</mx:Script>
<mx:Button label="Click Me" click="setValue()" />
</mx:Application>
Here, myValueChanged gets called whenever the myValue property changes. There are other ways, of course, but I often use this approach with good results. Hope it helps! Post back with questions and I'll keep an eye out.
Look into BindUtils class as back2dos suggests.
And, also, you can set the name of the event that will be triggered when a change is done to a property (default is propertyChange) like this:
[Bindable("change")]
var myProperty : SomeClass;
That is if ChangeWatchers adds listeners for the change event instead of propertyChange event. Which would be kind of weird, but not impossible with all the mishaps of the flex SDKs.
But again, I think BindUtils class should do the trick for you.
Use the class ObjectProxy or its subclass and wrap up the class that has a property you need to watch. In my example, I'm calling a func if someone is changing the property salary giving it a value of more than 55000 in an object Person:
package com.farata
{
import mx.utils.ObjectProxy;
import flash.utils.*;
use namespace flash_proxy;
public dynamic class MyPersonProxy extends ObjectProxy
{
// The object to wrap up
private var person:Person;
public function MyPersonProxy(item:Person){
super(item);
person=item;
}
flash_proxy override function setProperty(name:*, value:*):void {
if ( name == 'salary'&& value>55000) {
// add a new property to this instance of the
// class Person, which can be used in the calculations
// of the total compensation
setProperty("pension", 0.02);
}
super.setProperty(name, value);
}
}
}
well, the easiest way is to listen to PropertyChangeEvent.PROPERTY_CHANGE ... if you declare a property bindable, then mxmlc generates the code to dispatch this event ... if you let the compiler keep the generated ActionScript, then you'll see it ...
other than that, you might want to have a look at BindingUtils ...

Resources