How can I instantiate class from a swf? - apache-flex

I have an FLA file with objects in the library which I have set to be "classes" (In CS3, right click an item in the library select properties, make sure it's set to export for action-script, and has a class name)
For this exercise, let's call the class "MyClass"
If I publish that FLA to an SWC and SWF:
I can load the SWC statically, and instantiate "MyClass" by simply doing:
var inst:MyClass = new MyClasS();
Now, the problem: I'd like to be able to do this at runtime by loading the SWF file using a loader object.
I understand how to access instances which have been created by hand in the FLA before publishing, but what I want to be able to do, is create new instances of the class "MyClass".
I can get a "MovieClip" representing the swf file, I can add it to my displaylist, but I can't seem to get at the classes contained therein. (I hope this makes sense)
Any suggestions for how to attack this would be much appreciated.
Edit : Format code

To complete Christian's answer:
var cls : Class = loader.contentLoaderInfo.applicationDomain.getDefinition("ClassName");
var instance : Object = new cls();
Additionally, it's worth noting that you won't get strong typing (ie. it must be declared as Object) unless the class implements interface which is also defined in your main application. You will then be able to declare the instance variable as the interface and have compile-time access to it's members.

Have a look here; you should be able to extract a class reference by using Loader.contentLoaderInfo.applicationDomain.getDefinition("MyClass").

Related

Flex: load parent class into module

My main application contains a ClassA. The main application then loads a module and in that module I would like would to do:
var classA:InterfaceClassA = new ClassA();
It compiles fine but I get this warning:
Warning: YourApplication is a module or application that is directly referenced. This will cause YourApplication and all of its dependencies to be linked in with module.YourModule:Module. Using an interface is the recommended practice to avoid this.
I can't use an interface to generate the new instance, so what is the correct way to do this?
I found an answer in Accessing the parent application from the modules . I created a helper class in the main Application that contains instances of the classes I want to access. In the module I then use:
parentApplication.myModuleHelper.**myClassInstance**.myMethod();
for instance methods and for static class level methods I use:
parentApplication.myModuleHelper.**MyClassInstance**.myMethod()
To get an instance of my class in a module I use this in MyModuleHelper
public function getFullScreenUtil(iFullScreenUtil:IFullScreenUtil , iSystemManager:ISystemManager):FullScreenUtil {
return new FullScreenUtil(iFullScreenUtil , iSystemManager);
}
and this in MyModule:
var _fullScreenUtil:* = parentApplication.moduleHelper.getFullScreenUtil(this , systemManager);
which is all I need for now. I am not sure how I could cast the result of getFullScreenUtil(..) to an actual instance of FullScreenUtil but I expect that it can not be done in modules. Maybe using an interface would provide the solution to that.

access mxml component from external actionscript file

i'm trying to access an mxml component from my external as file. e.g
main.mxml:<br>
<code>[mx:text id="myText" />]</code>
file.as:<br>
<code>var mainM:main = new main();
mainM.text.visible = true;</code>
I get the following error:
[TypeError: Error #1009: Cannot access a property or method of a null object reference]
Any suggestions on how to approach it better.
The ID of your component instance becomes a member of your application and can easy be accessed like so
import mx.core.Application;
mx.core.Application.application.myText.visible = true;
An additional answer is that when you create a new Flex component (new myFlexComponent()), the child UI components are not created until a CREATION_COMPLETE call is invoked, indicating the component is fully created. In the case of application, there is only one, and its automatically created by the framework, and referenced by (Application.application) as stated above.
For example, if your variable was a simple class variable (e.g. myDate:Date), you could access it via the above syntax

Flex/AS3 : Automatically instantiate package classes in an array (plugin classes)

This is my first time here, but I already found some good answers here, so I'd like to thank everyone.
I'm developping a small Flex application and I want to instantiate every class from a package into an array, so I can parse it afterwards. To clarify, I'm trying to ease a plugin management system for my application, with the old canProcess/doProcess routine :
My plugins are all in ONE package, including an abstract plugin class. First, I create one instance of every classes in this package (that's where I need help) and put them in an array. Then, whenever I need a plugin for an item, I parse every plugin class in my array with the canProcess method (the item is the parameter). If one plugin says yes, then I send the item to the doProcess method and stop parsing the array.
I know I could implement by hand every class in my package, but I'd prefer not bothering to do it.
Has anyone an idea ?
Thx
AS3 reflection doesn't allow you to list all classes in a package. You will have to write the class names to an (xml) file at the server, load it and then use getDefinitionByName to get Class objects from those strings and then instantiate them.
Consider the sample xml file:
<root package="boris.ratak">
<className>Plugin1</className>
<className>Plugin2</className>
<className>Plugin3</className>
</root>
load it with URLLoader and parse it like:
import flash.utils.getDefinitionByName;
var pack:String = String(xml.#package) + ".";
for each(var cl:String in xml.className)
{
var name:String = pack + String(cl.text());
var Type:Class = getDefinitionByName(name) as Class;
pluginArray.push(new Type());
}

Create instances of flex custom component by passing in type

In my flex app there are a few custom components. I want to create instance of these components at runtime and assign them properties by reading in a config file.
I know how to read xml and instantiate components, however my question is about being able
to get the type of the component from the xml attribute and then creating an instance of that type.
My xml looks like this:
You can instantiate an arbitrary named type through ActionScript's "reflection API":
var clazz:Class = Class(getDefinitionByName("class.from.your.xml.file.Name"));
var component:Object = new clazz();
http://livedocs.adobe.com/flex/3/langref/flash/utils/package.html#getDefinitionByName()
If you get an error about the type not existing, this is because it isn't linked from elsewhere in your application and the compiler only adds classes that are referenced. You can work around this using the following compiler arg:
includes class [...]
Links one or more classes to the resulting application SWF file, whether or not those classes are required at compile time.
http://livedocs.adobe.com/flex/3/html/compilers_14.html#157203

Using external SWFs in a Flex application - duplicating MovieClip?

I'm working on an Flex application which uses many objects, e.g. LEDs, bulbs, gauges created in Flash. The objects internally consist of several small MovieClips and have their own logic inside. One of the initial requirements was that the objects have to be loaded at runtime, thus they were exported as SWF, not SWC. However, we ran into problem when we tried to duplicate loaded SWF. It turned out that MovieClip class doesn't have neither copying constructor nor method that would allow us to clone existing MovieClip. This way we'd end up loading an object every time from hdd, which involves a lot of overhead. Is it possible that language like ActionScript 3 doesn't have such a mechanism? Have we missed something out? If not, am I correct that the only solution is to use Flash Component Kit, make some custom components and include them as SWC at compile time?
After you load the MovieClip is it possible to use getDefinitionByName() as shown here?
http://livedocs.adobe.com/flex/3/langref/flash/utils/package.html#getDefinitionByName()
You are correct in that there is no built in way to duplicate a movieclip.
There are however work arounds. The esiest way as I see it is to give the movieclips classes.
You don't have to make the actual classes. Just write any name in the class field when setting up linkage on the top most movieclip that needs to be copied.
So a name for you LED movieclip, another name for the bulb etc.
The benifit is that now you have a class that you can initiate objects from.
No when you grap one of the movieclips you can duplicate it with the following method:
public function DuplicateDisplayObject(dO:DisplayObject):DisplayObject
{
if(dO == null)
return null;
var dOClass:Class = Object(dO).contructor;
return DisplayObject(new dOClass());
}
This assumes of cause that you can actually get a hold of one of the movieclips first. And mind you that it doesn't copy the state of the movieclip.
Another more importent note is that this only works if the you link the movieclips to classes. The classes doesn't have to exist (flash will create empty classes for you).
Other solutions could be:
Compiling against the classes without
including them (see the
"external-library-path" tag for the
flex compiler), and load the them at
runtime (from swf).
Compiling against the classes as a
RSL (Runtime Share Library) the swc
will be loaded at runtime.
Adobe has more info on how to do that, should be easy to find on their website.
A more exotic solution would be copy the bytecode of an object. Not sure if that would work with something on the displaylist, properly not.
About the solution using getDefinitionByName():
If I remember correctly you still need to give the movieclips fake classes, since getQualifiedClassName only returns MovieClip class. But I could be wrong.
Another solution:
private function duplicateImg(sourceLoaderInfo:LoaderInfo, target:Image):void
{
var ba:ByteArray = sourceLoaderInfo.bytes;
var dupCliploader:Loader = new Loader();
dupCliploader.contentLoaderInfo.addEventListener(
Event.COMPLETE, bytesLoaded);
dupCliploader.loadBytes(ba);
}
private function bytesLoaded(event:Event):void
{
var mc:MovieClip = event.currentTarget.content as MovieClip;
_img.source = mc;
_img.width = mc.width;
_img.height = mc.height+5;
}

Resources