as3 / flex interface incompatibility when loading external swf - actionscript-3

I have a main project, and i want to load another project's swf into it:
//loader code in Main class of main project
var url:URLRequest = new URLRequest("../src/components/TextTool.swf");
var ttWrapper:UIComponent = new UIComponent();
var ldr:SWFLoader = new SWFLoader();
var context:LoaderContext = new LoaderContext();
if (Security.sandboxType == Security.LOCAL_TRUSTED) {
context.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
} ldr.source = "../src/components/TextTool.swf";
ldr.loaderContext = context;
ldr.addEventListener(Event.COMPLETE, onLoadComplete);
ldr.load();
can.addElement(ldr);
Here's the code of the Main class of the second project:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:stark="stark.*" name="textModule" >
<stark:TextTool name="myTF" id="myTF"></stark:TextTool>
</s:Application>
Now both of the projects contain an interface file : IModule, with the same code, and an element of the second project (the one that's being loaded) which is an instance of my custom class "TextTool", which extends s:Group and implements IModule:
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="400"
xmlns:com="src"
height="130" creationComplete = "initText()" implements="IModule"></s:Group>
Now as soon as i've loaded the swf, i want to access that TextTool instance which has and id of "myTF" :
//Code in the main class of the main project
trace(getQualifiedClassName(mySwf.getChildByName('textModule')['myTF']));
trace(mySwf.getChildByName('textModule')['myTF'] is IModule);
//output:
//stark::TextTool
//false
As i've mentioned above, i have the interface in both projects, same code, it has the same path relative to main classes, and myTF does extend IModule. After the swf is loaded, i get the right element, but i still get false when verifying if it implements IModule.
Why?

You're testing Application for implementation
trace(mySwf.getChildByName('textModule') is IModule);
I think you forgot to add ['myTF']
trace(mySwf.getChildByName('textModule')['myTF'] is IModule);

You're loading both into different ApplicationDomains, so whichever loads first wins. Try loading them into the same ApplicationDomain.

Related

Item Renderer not Working correctly in Spark List

I used flex sdk 4.5 for creating Adobe Air application. My application download files one by one. I show the currently downloading, pending and completed files in spark list. I used item Renderer that show the progress of the file and other states.
It works fine if selected files fit in current view. But as number of downloads increase, the Spark list shows vertical scroll. here I have the problem. Here file downloading functionality works fine, but if I try to scroll the list, File titles mix up or displayed out of order.
item renderer code:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="onInit()"
>
<fx:Script><![CDATA[
import com.streamingnetworks.hdvrwin.vo.DownloadInfo;
import mx.events.CloseEvent;
[Bindable]private var downloadInfo:DownloadInfo;
private var url:String = "";
private var fileName:String = "";
private function onInit():void
{
downloadInfo = data as DownloadInfo;
downloadInfo.addEventListener("Progress", onProgress);
downloadInfo.addEventListener("DownloadComplete", onComplete);
prog.label = "Downloading %3%%";
lblPath.text = " - " + downloadInfo.getPathIp();
trace("Downloading: " + downloadInfo.name);
}
private function onProgress(e:Event):void
{
prog.setProgress(downloadInfo.downloadedBytes, downloadInfo.totalBytes);
lblState.text = downloadInfo.getDownState();
}
private function onComplete(e:Event):void
{
prog.label = "Download Complete";
}
protected function onClose(event:CloseEvent):void
{
downloadInfo.state = "deleted"
}
]]></fx:Script>
<s:TitleWindow top="0" left="0" right="0" bottom="0" dropShadowVisible="false"
title="{'Downloading ' + downloadInfo.name}" close="onClose(event)">
<mx:ProgressBar id="prog" label="" mode="manual"
trackHeight="20" labelPlacement="center" width="100%"/>
<s:HGroup top="25">
<s:Label id="lblState" text="Downloading 0 Bytes of 0 Bytes."/>
<s:Label id="lblPath"/>
</s:HGroup>
</s:TitleWindow>
</s:ItemRenderer>
here the list control where I am using that renderer
<s:List id="lstControls" dataProvider="{urlArr}"
itemRenderer="ItemRenderer"
left="5" right="5" bottom="5" top="40"/>
urlArr is an arrayList that contains only url in string form.
How can I solve this problem? Any Help will be appreciated. Thanks
Your renderers are not updating correctly because you are setting your data when the renderer is created - but you should be overriding the set data method, eg:
override public function set data(value:Object):void
{
super.data = value;
downloadInfo = data as DownloadInfo;
downloadInfo.addEventListener("Progress", onProgress);
downloadInfo.addEventListener("DownloadComplete", onComplete);
prog.label = "Downloading %3%%";
lblPath.text = " - " + downloadInfo.getPathIp();
trace("Downloading: " + downloadInfo.name);
}
And remove the creationComplete listener.
As a better practice. Have all the data your progress bars will need all ready in the data provider and have them react ONLY to changes in the data. Adding and removing listeners and binding internally will only cause you grief. Renderers do not live forever and are re-used inside of list components. Manage everything through overriding set data().
In this example I would create a model object with a name like FileDownloadInfo and properties such as .downloadProgress .fileName and .ipAddress then have the renderer update on property change events of .downloadProgress

How do you upload a photo in Flex 3?

In Flex 3 how to upload a photo ssing Browse and Upload option?
In Flex 4 there is an option like:
<net:FileReference id="fileReference"
select="fileReference_select(event);"
complete="fileReference_complete(event);" />
But in Flex 3 there is no <net> tag.
EDIT:
This is my Button click handler code
protected function uploadProfileImage(event:MouseEvent):void
{
var fileRef:FileReference= new FileReference();
browseButton.addEventListener(MouseEvent.CLICK, onButtonClick);
function onButtonClick(e:MouseEvent):void {
fileRef.browse([new FileFilter("Images", "*.jpg;*.gif;*.png")]);
fileRef.addEventListener(Event.SELECT, onFileSelected);
Alert.show("0")
}
function onFileSelected(e:Event):void {
fileRef.addEventListener(Event.COMPLETE, onFileLoaded);
//fileRef.load();
Alert.show("1");
}
function onFileLoaded(e:Event):void {
var loader:Loader = new Loader();
loader.loadBytes(e.target.data);
//addChild(loader);
profileImage.data = loader.content;
profileImage.width = loader.width;
profileImage.height = loader.height;
this.height = profileImage.height;
this.width = profileImage.width;
this.visible = true;
Alert.show("2");
}
There's no <net> tag in Flex 4 either. The net part in <net:FileReference... is an xml namespace. There are a bunch defined at the top of your application's MXML file. Here's a sample from a Flash-based Flex 4 app:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
The xmlns:s="library://ns.adobe.com/flex/spark" is just mapping all the Spark components to the s namespace which allows you to reference Spark components like Button in MXML like this:
<s:Button label="My Button"/>
In the case of Spark Adobe has provided a manifest file that maps the fully qualified Spark packages to the familiar MXML names (this question has an example of such a file). You can also map AS3 package names to an xml namespace.
FileReference is in the flash.net package. You can bind that package to the net namespace by adding the following to the root tag in your MXML file:
xmlns:net="flash.net.*"
Once you do that you can reference classes in the flash.net package in MXML by prefixing them with "net" ala <net:FileReference....
Of course, FileReference doesn't inherit UIComponent so you won't be able to add it directly to your application. So that's probably not what is happening in your case.
Without seeing more than what you've posted I suspect that the FileReference in your question is a custom component that has it's package bound to the net xmlns.
Can you post the complete MXML document that has the <net:FileReference... tag in it?
EDIT
Using the code you added, in your script block have this:
var fileRef:FileReference = new FileReference();
function onButtonClick(e:MouseEvent):void {
fileRef.browse([new FileFilter("Images", "*.jpg;*.gif;*.png")]);
fileRef.addEventListener(Event.SELECT, onFileSelected);
fileRef.addEventListener(Event.CANCEL, onFileCanceled);
}
function onFileSelected(e:Event):void {
fileRef.removeEventListener(Event.SELECT, onFileSelected);
fileRef.removeEventListener(Event.CANCEL, onFileCanceled);
fileRef.addEventListener(Event.COMPLETE, onFileLoaded);
fileRef.load();
}
function onFileCanceled(e:Event):void {
fileRef.removeEventListener(Event.SELECT, onFileSelected);
fileRef.removeEventListener(Event.CANCEL, onFileCanceled);
}
function onFileLoaded(e:Event):void {
fileRef.removeEventListener(Event.COMPLETE, onFileLoaded);
var loader:Loader = new Loader();
loader.loadBytes(e.target.data);
profileImage.data = loader.content;
profileImage.width = loader.width;
profileImage.height = loader.height;
profileImage.visible = true;
}
Then in your MXML have something like:
<mx:Button
label="Click to Load Profile Image"
click="onButtonClick(event)"/>
<mx:Image
id="profileImage"
visible="false"/>
EDIT 2
If you are having problems with calling load() on FileReference make sure you are targeting the correct Flash Player. This answer explains how to do that in Flash Builder. IIRC, Flex 3 projects target Flash Player 9 be default.

How to run a function after the canvas has changed in ActionScript 3.0?

Please understand: I am a total beginner at Actionscript and anything like Actionscript, and though I generally have some idea of what I'm doing as a programmer, I'm having some setbacks in self-learning this language and Flex Builder. Right now I'm trying to make a very simple implementation where a label effectively has its text added to multiple times over the first few seconds that the program is run. The problem I'm running into is that I can't just put all that into one function + one call on that function, as changes to the label's text are apparently not seen until that function runs its full course.
So I tried using a viewstack and cloning the canvas a few times, giving each canvas's version of that label a different bit of text. Then I set the initialize function for the viewstack to change the canvases on regular intervals over the first few seconds. But that didn't work either, as the difference isn't seen until the function runs its full course.
So then I tried putting function calls on the individual canvases' initialize attributes, and those functions aren't being called at all apparently.
What the heck? I know this probably isn't even the way that you're supposed to animate something in ActionScript or Flex, but I still would like to know how to approach the problem this way for future reference. What am I missing? Thanks!
As you've noticed, changes to the displayed output of your program can't happen in the middle of executing a function that you've written. ActionScript is single-threaded, which means that none of the framework code that updates the screen can run while your function is running.
If you're interested in learning exactly what happens in order to update the screen, do a search for "flex component lifecycle" and read some of the stuff you find. It's a bit advanced, but it was the thing that really helped me understand how the Flex framework works.
Anyway, on to your real question - how to animate something. There are many ways, but for your case of progressively adding text to a label, I'd probably use the Timer class.
Here is an example:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private var timer:Timer;
private var words:Array = ["The", "quick", "brown", "fox"];
private function startTimer(event:FlexEvent):void
{
timer = new Timer(1000, 1);
timer.addEventListener(TimerEvent.TIMER, updateText);
timer.start();
}
private privatefunction updateText(event:TimerEvent):void
{
theLabel.text += words.shift() + " ";
if (words.length > 0)
{
timer.reset();
timer.start();
}
}
]]>
</fx:Script>
<s:Label id="theLabel" text="" creationComplete="startTimer(event)"/>
</s:Application>
A basic approach would be to use data binding for the label value, and setTimeout() or setInterval() to cause the delay between updates.
Here is an example:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
initialize="init()"
minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
[Bindable]
private var displayString:String = "Detonation in ";
private var count:int = 5;
private var timer:uint;
private function init():void {
timer = setInterval(updateDisplay, 1000);
}
private function updateDisplay():void {
displayString += count + ".. ";
if (--count == 0) {
clearInterval(timer);
}
}
]]>
</fx:Script>
<s:Label text="{displayString}"/>
</s:Application>

AIR Application

I have my AIR application i.e MyAIRApplication ready. I am trying to make a splash screen for it.
Here's my code so far ..
main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="showSplash()"
visible="false"
layout="absolute"
showFlexChrome="false">
<mx:Script>
<![CDATA[
import components.Splash;
import mx.core.Window;
import mx.controls.Alert;
import mx.events.AIREvent;
private var splash:Window;
private var splashTimer:Timer;
private function showSplash():void {
splash = new Splash();
splash.systemChrome = "none";
splash.transparent = true;
splash.type = NativeWindowType.LIGHTWEIGHT;
splash.addEventListener(AIREvent.WINDOW_COMPLETE, boot);
splash.open();
}
private function boot(event:AIREvent):void {
splashTimer = new Timer(3000, 2);
splashTimer.addEventListener(TimerEvent.TIMER_COMPLETE, showApp);
splashTimer.start();
this.removeEventListener(AIREvent.WINDOW_COMPLETE, boot);
}
private function showApp(event:Event):void {
splash.close();
splash = null;
splashTimer.stop();
splashTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, showApp);
splashTimer = null;
// My Application .. where I wrote all components
var mainWin:WindowedApplication = new MyAIRApplication();
mainWin.activate();
mainWin.visible = true;
}
]]>
</mx:Script>
</mx:WindowedApplication>
Splash.mxml :
<?xml version="1.0" encoding="utf-8"?>
<mx:Window xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="400" height="300"
showFlexChrome="false" >
<mx:Image x="0" y="0" width="600" height="400" source="#Embed('../images/splash-bg.png')" scaleContent="false"/>
</mx:Window>
But I am facing 2 problems :
My AIR application ( i.e MyAIRApplication ) is not showing up, on completing the splash screen.
My Splash Screen is getting shown on top left corner always
Can anyone please provide me with a solution ?
var mainWin:WindowedApplication = new MyAIRApplication();
WindowedApplication isn't created like this. You already have one when your app start, use it. Just make its contents hidden to be shown after the splash.
Also I'm not sure that closing splash window with splash.close() will fire WINDOW_COMPLETE event, check this too with trace (rewrite to Event.CLOSE if needed.)
Windows aren't centered by default. Get screen size with Capabilities.screenResolutionX/Y, calculate x/y for centered window and call splash.move(x, y).
It also might have something to do with you casting your splash var as type Window,
private var splash:Window;
But then instantiating it as a new Splash
private function showSplash():void {
splash = new Splash();
They should both be either Window or Splash.

flashvars not loading in Flex 4.5 application in Adobe Flash Builder

I am following this adobe flashvars example to try and get flashvars loading in my flex 4.5 application. However, the code is not working. I don't really understand what I'm doing wrong, or differently from the example. here is my index.template.html code (in the html-template folder) which uses swfobject to load the application:
function embedPlayer() {
var flashvars = {};
flashvars.userLoggedIn = true;
flashvars.test = "hello";
embedSWF(SWF_FILE, SWF_ID, SWF_WIDTH, SWF_HEIGHT, "9.0", "playerProductInstall.swf", flashvars);
}
And here is the simplified code from my flex application:
<?xml version="1.0" encoding="utf-8"?>
<s:Application
xmlns:d="http://ns.adobe.com/fxg/2008/dt"
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:c="components.*"
initialize="mainInit()"
creationComplete="doCreationComplete()"
applicationComplete="_initializer.applicationComplete()"
xmlns:application="components.application.*"
xmlns:gui="com.gui.*" xmlns:main="com.gui.components.main.*" xmlns:photoTray="com.gui.components.main.photoTray.*">
<fx:Style source="/assets/all.css" />
<fx:Script>
<![CDATA[
import com.gui.components.main.Initializer;
import com.gui.components.main.LayoutsController;
import mx.core.FlexGlobals;
private var _initializer:Initializer;
private var _layoutsController:LayoutsController;
public var userLoggedIn:Boolean;
private function mainInit():void {
_initializer = new Initializer(this);
}
private function doCreationComplete():void {
_initializer.init();
var params:Object = FlexGlobals.topLevelApplication.parameters;
//userLoggedIn = params.userLoggedIn;
_layoutsController = new LayoutsController(this);
}
]]>
</fx:Script>
</s:Application>
I call FlexGlobals.topLevelApplication.parameters (after creationComplete) to try and access flashvars, which is what adobe says is the way to do it in flex 4.5. From my research using Application.application.parameters and root.loaderInfo.parameters are both deprecated.
Does anyone see what I am doing wrong? My application works fine in flash builder except for flashvars loading on creationComplete.
Thanks
This is how I do it in flex 3 not sure it applies to flex 4.5
Application.application.parameters.userLoggedIn
Also on this line
//userLoggedIn = params.userLoggedIn;
The value of any flash var is a string which you are trying to assign a Boolean.
So do this.
//userLoggedIn = Boolean(params.userLoggedIn);