clone flex component - apache-flex

I am trying to duplicate a flex component at run time.
For example if i have this
mx:Button label="btn" id="btn" click="handleClick(event)"/>
i should be able to call a function called DuplicateComponent() and it should return me a UI component thts exactly same as above button including the event listeners with it.
Can some one help me please??
Thanks in advance

Do a Byte Array Copy. This code segment should do it for you:
// ActionScript file
import flash.utils.ByteArray;
private function clone(source:Object):*
{
var myBA:ByteArray = new ByteArray();
myBA.writeObject(source);
myBA.position = 0;
return(myBA.readObject());
}
One note, I did not write this code myself, I'm pretty sure I got it from a post on the Flex Coder's list.

To solve that problem you should use actionscript and create the buttons dynamically.
Lets say you want the button(s) to go in a VBox called 'someVbox'
for (var i:uint = 0; i< 10; i++){
var but:Button = new Button();
but.label = 'some_id_'+i;
but.id = 'some_id_'+i;
but.addEventListener(MouseEvent.CLICK, 'handleClick');
someVbox.addChild(but);
}
I haven't tested it, but that should add 10 buttons to a vbox with a bit of luck.

You can't take a deep copy of UIComponents natively. You're best bet would be to create a new one and analyse the one you have to add a duplicate setup. To be honest this does sound like a bit of a code smell. I wonder if there may be a better solution to the problem with a bit of a rethink..

Same question as: http://www.flexforum.org/viewtopic.php?f=4&t=1421
Showing up in a google search for the same thing. So you've cut&pasted the same question a month later. No luck eh?
There is no easy way to do this that I know of. Many of a component's settings are dependent on the container/context/etc... and get instantiated during the creation process, so there's no reason to clone from that perspective.
You can clone key settings in actionscript and use those when creating new elements.
For instance, assuming you only care about properties, you might have an array ["styleName","width","height",...], and you can maybe use the array like this:
var newUI:UIComponent = new UIComponent();
for each(var s:String in propArray) {
newUI[s] = clonedUI[s];
}
If you want more bites on your question (rather than waiting a month), tell us what you are trying to achieve.

mx.utils.ObjectUtil often comes in handy, however for complex object types, it's typically good practice to implement an interface that requires a .clone() method, similar to how Events are cloned.
For example:
class MyClass implements ICanvasObject
{
...
public function clone():ICanvasObject
{
var obj:MyClass = new MyClass(parameters...);
return obj;
}
}
This gives your code more clarity and properly encapsulates concerns in the context of how the object is being used / cloned.

You are right but as per my understanding UI Components are not cloned by mx.utils.ObjectUtil.
from : http://livedocs.adobe.com/flex/201/langref/mx/utils/ObjectUtil.html#copy()
copy () method
public static function copy(value:Object):Object
Copies the specified Object and returns a reference to the copy. The copy is made using a native serialization technique. This means that custom serialization will be respected during the copy.
This method is designed for copying data objects, such as elements of a collection. It is not intended for copying a UIComponent object, such as a TextInput control. If you want to create copies of specific UIComponent objects, you can create a subclass of the component and implement a clone() method, or other method to perform the copy.
Parameters value:Object — Object that should be copied.
Returns Object — Copy of the specified Object

Related

Flex: NPE and Proper way to access component properties before creation complete

I think I'm missing something important about flex sdk component lifecycle, but cannot sort it out, although read a lot of tutorials. Could you please share your experience on how do you operate with flex visual object's properties and how do you avoid NPE when accessing them before component creation complete.
Let's say we have a simple component MyTitleWindow.mxml:
<s:TitleWindow>
<s:DataGrid id="myDataGrid" />
</s:TitleWindow>
Another component got data from a remote object, and wants to apply the data into title window's datagrid and show it via PopUpManager:
private function handleDataReceived(data : ArrayCollection) : void {
var myTitleWindow : TitleWindow = new MyTitleWindow();
PopUpManager.addPopUp(myTitleWindow);
myTitleWindow.myDataGrid.dataProvider = data;
}
Ofcourse, the line myTitleWindow.myDataGrid.dataProvider = data will throw an NPE because we're trying to access myDataGrid that haven't been rendered yet.
Currently I can see only 2 options how to avoid NPE:
Create a setter for data in titleWindow, put the data into some
cache. Listen to creationComplete event, in it's handler apply data
from the cache to the datagrid. This approach works fine, but I'm
tired of adding this safe-guards across the application.
Make a
bindable property - works for me only with simple datatypes
(numbers, strings...)
Is there anything I'm missing in the area of using flex validation/invalidation cycle that could help to avoid excessive code?
The problem you are having and Crusader is reporting is because in Flex components are initialized lazy. This is generally a good thing but in your case it is what's causing your problems.
In general I wouldn't suggest to set the dataProvider on a view component from outside the component as you have no way of knowing if all is setup and ready to use.
What I usually do. In simple cases I simply add a public propberty which I make [Bindable]. The (i think) cleaner way would be to create a setter (and getter) and so save the dataProvider in a local variable (in your case probably ArrayCollection). In the setter I usually check if the "myDataGrid" exists and if it exists, to additionally set the dataProvider property. I would then add a CreationComplete callback in my component and in that I would also set the dataProvider.
So when setting the dataProvider before the component is finished initializing, the value would simply be saved in the local variable and as soon as it is finished setting up the dataProvider is automatically set. If the component is allready setup (you are changing the dataProvider) the setter would automatically update the dataProvider of "myDataGrid"
<s:TitleWindow creationComplete="onCreationComplete(event)">
...
private var myDataProvider:ArrayCollection;
private function onCreationComplete(event:FlexEvent):void {
myDataGrid.dataProvider = myDataProvider;
}
public function set myDdataProvider(myDataProvider:ArrayCollection):void {
myDataProvider = myDataProvider;
// Only update the dataProvider if the grid is available.
if(myDataGrid) {
myDataGrid.dataProvider = myDataProvider;
}
}
....
<s:DataGrid id="myDataGrid" />
</s:TitleWindow>
Yeah, this can be an annoyance, and it's not just with popups. It can also be a pain when using a ViewStack components with a default creationpolicy, which I tend to do fairly often.
I might get flamed for this, but I usually just use bindings. I'm not sure what you mean by "simple datatypes" - it works fine with custom types too. You'd have to provide an example.
One thing you could do (and I'll probably get flamed for this :p ) is create your popup component instance early on and re-use it rather than creating a new one each time.
No, I don't think you're "missing something" in the component lifecycle.
I always try to invert the responsibility for setting a dataProvider and prefer to have components observe a [Bindable] collection.
In simple examples such as yours I avoid giving my components an id. This prevents me from breaking encapsulation by referring to them externally.
<s:TitleWindow>
<s:DataGrid dataProvider="{data}" />
</s:TitleWindow>
The consumers of your MyTitleWindow component should not know that it has a DataGrid with id 'myDataGrid', or be required to set the dataProvider property of 'myDataGrid'.
Considering components declared in MXML require a no-arguement constructor (and that we're unable to declare multiple constructors) - one approach that has worked well for me in the past is to offer a static 'newInstance' method. I give this method a relevant name based on the domain I'm working in, and also any required parameters.
public static function withData(data : ArrayCollection) : MyTitleWindow
{
var myTitleWindow : MyTitleWindow = new MyTitleWindow();
myTitleWindow.data = data;
return myTitleWindow;
}
This clearly communicates the 'contract' of my component to any and all consumers. (Obviously things become clearer with more relevant naming).
private function handleDataReceived(data : ArrayCollection) : void
{
PopUpManager.addPopUp(MyTitleWindow.withData(data));
}

Is there any difference of reset an ArrayCollection by set it's source or change it's reference

I have two ArrayCollection now (a, b) and a is set bindable. I want to reset a with b.
The old code in our project is like:
a = new ArrayCollection();
for (var i:int = 0; i < b.length; i++) {
a.addItem(b.getItemAt(i));
}
Then, I think it may cause a potential memory leak. So I changed it to:
a.removeAll();
for (var i:int = 0; i < b.length; i++) {
a.addItem(b.getItemAt(i));
}
Then I read a topic: Flex optimization tip: ArrayCollection.removeAll() vs. ArrayCollection.source = new Array(). Is this a bug ?
It says removeAll() will cause a performance problem when the data set is large.
So does it means there is a trick off? If the data set is small I should use removeAll, and if the data set is large, I should not use removeAll()?
Another question, I also read a topic about Changing the source of an ArrayCollection.
It says if directly use a = b, "it will kill all the databound controls that are listening to events on the ArrayCollection instance". I don't understand this. I tried a = b, and it works ok (the view that use a as dataprovider updates).
What's the difference between using a=b and a.source = b.source?
I'm new to Flex. Thanks in advance.
ArrayCollection is a wrapper class around Array, and underlying Array can be access using source property
The ArrayCollection class is a wrapper class that exposes an Array as
a collection that can be accessed and manipulated using the methods
and properties of the ICollectionView or IList interfaces. Operations
on a ArrayCollection instance modify the data source; for xample, if
you use the removeItemAt() method on an ArrayCollection, you remove
the item from the underlying Array.
so one should always use Source property of ArrayCollection, if have populated Array
i suggest to declare b as Array not as ArrayCollection and initialize a as
a = new ArrayCollection(b); or
a= new ArrayCollection();// Default constructor ArrayCollection(source:Array=null);
a.source = b; //updates data in Arraycollection
Data Binding means bound controls with datasource(could be any thing like functions, objects, other control, Array, XML, Collection, List etc)
Data binding is the process of tying the data in one object to another
object. It provides a convenient way to pass data between the
different layers of the application. Data binding requires a source
property, a destination property, and a triggering event that
indicates when to copy the data from the source to the destination. An
object dispatches the triggering event when the source property
changes.
Data Binding could be harmful for application with large data because it would creates multiple changes events and both getter and setter executes on change, which need extra proccessing so it would be good practice to shorter scope of a and provide data directly to source as
private function handler_B_DataChange(event:Event)
{
var a:Arraycollection = new ArrayCollection(b);
controlA.dataProvider = a;
//or just
controlB.dataProvider = new ArrayCollection(b);
}
Details of binding could be view on Binding to functions, Objects, and Arrays
Hopes that Helps
I would also try:
a.removeAll();
a.addAll(b.list);
When you declare:
a = new ArrayCollection()
it loses the pointer to the "old" ArrayCollection where it is binded to your application. Thus, that is why when you do "new ArrayCollection" the binding doesn't work anymore. However, in your example, you're not creating a "new ArrayCollection"... you're just replacing the objects in that ArrayCollection with something else... So the binding still works.
If you have data that is into the thousands, you might want to consider implementing a pagination of some sort. If it's just a couple hundred, then I don't think you need to worry too much about the performance of a.removeAll();

Designing a Generic Toolmanager

I want to handle multiple operations on a UI Component (button ,textfield, swfs,custom objects etc)
in like scaling,skewing ,color,rotations etc etc and save them too. Earlier the actions were done
using a single tool and single mxml file but now the tool is separated into different tools.
Was wondering how i can design / use something like Toolmanager class to handle actions etc?
Also the tricky part is that some objects can have more operations defined for them .
Like 'object1' has 3 operations that can be performed on it and 'object2' has 5 operations defined on it.
We are using MVC design pattern but no frameworks as such.
What are the different design patterns that can be used to do this?
Edit:
To be more precise i want implement this in AS3 OO way.
The application is similar to drawing application which supports addition of various images,text,audio,swfs etc. One added user can perform various operations of the objects..like
adding color,scaling skewing,rotation etc etc and custom effects and after that export the drawing as PNG.Likewise some effects that are applicable to text are not applicable to images
and vice versa. and some effects can be common.
Any ideas?
Probably you could have a toolbar, tools(inheriting from a common base), and some kind of property panel, these objects are accessible from a manager class which wrappes them together and makes some variables accessible for all classes.
Probably you want a selection array or vector in the manager class and a select tool to manipulate this collection
like (in the manager)
protected var _selection:Vector.<EditableBase> = new Vector.<EditableBase>();
public function get selection() { return _selection;}
and a collection about the editbase extensions and the tools avaiable for them.
every time the selection tool updates the selection collection (probably calling a method on manager from the select tool's onMouseUp method) you can update the toolbar to display the apropriate tools for the current selection
(in manager)
protected var _ToolsByType:Object (or Dictionary) = {"EditableAudio": ["toolA", "toolB", etc]};
protected var _defaultSet:Array = ["toolA", "toolB"];
and after the selection has benn manipulated (in manager also)
public function onSelectionChangedCallback():void
{
var toolsToDisplay:Array = _defaultSet;
if(_selection.length == 1)
{
//not actual syntax
var type:String = getQualifiedClassName(_selection[0]);
if(type in _ToolsByType) toolsToDisplay = _ToolsByType[type];
}
myToolBar.showSet(toolsToDisplay);
}
the ancestor for the tools should look something like this:
public class ToolBase
{
protected var _manager:ToolManager;
function ToolBase(manager:ToolManager)//and probably a bunch of other params as well
{
_manager = manager;
}
function onSelect()
{
//you can manipulate the properties panel here
}
function onDeSelect()...
function onMouseDown(mouseData:event/whateverWrapperYouHaveCreated)...
function onMouseMove...
function onMouseUp...
}
and so and so on :)
kinda straight forward.
check photoshop plugin tutorials, or google around "extending {any adobe stuff here, like flash or something}
thats javascript but the concept can be applied here as well
maybe you could use the Strategy Design Pattern by creating some extra classes in your MVC implementation
http://en.wikipedia.org/wiki/Strategy_pattern
algo, check this tool for images:
http://www.senocular.com/demo/TransformToolAS3/TransformTool.html
bye! :)

Fastest way to get an Objects values in as3

Ok, so I swear this question should be all over the place, but its not.
I have a value object, inside are lots of getters/setters. It is not a dynamic class. And I desperately need to search an ArrayCollection filled with them. The search spans all fields, so and there are about 13 different types of VOs I'll be doing this with.
I've tried ObjectUtil.toString() and that works fine and all but it's slow as hell. There are 20 properties to return and ObjectUtil.toString() adds a bunch of junk to the output, not to mention the code is slow to begin with.
flash.utils.describeType() is even worse.
I'll be pleased to hear I'm missing something obvious.
UPDATE:
I ended up taking Juan's code along with the filter algorithm I use for searching and created ArrayCollectionX. Which means that every ArrayCollection I use now handles it's own filters. I can search through individual properties of the items in the AC, or with Juan's code it handles full collection search like a champ. There was negligible lag compared to the same solution with external filters.
If I understand your problem correctly, what you want is a list of the getters defined for certain objects. As far as I know, you'll have to use describeType for something like this (I'm pretty sure ObjectUtils uses this method under the hood).
Calling describeType a lot is going to be slow, as you note. But for only 13 types, this shouldn't be problematic, I think. Since these types are not dynamic, you know their properties are fixed, so you can retrieve this data once and cache it. You can build your cache up front or as you find new types.
Here's is a simple way to do this in code:
private var typePropertiesCache:Object = {};
private function getPropertyNames(instance:Object):Array {
var className:String = getQualifiedClassName(instance);
if(typePropertiesCache[className]) {
return typePropertiesCache[className];
}
var typeDef:XML = describeType(instance);
var props:Array = [];
for each(var prop:XML in typeDef.accessor.(#access == "readwrite" || #access == "readonly")) {
props.push(prop.#name);
}
return typePropertiesCache[className] = props;
}

AS3 Memory Conservation (Loaders/BitmapDatas/Bitmaps/Sprites)

I'm working on reducing the memory requirements of my AS3 app. I understand that once there are no remaining references to an object, it is flagged as being a candidate for garbage collection.
Is it even worth it to try to remove references to Loaders that are no longer actively in use? My first thought is that it is not worth it.
Here's why:
My Sprites need perpetual references to the Bitmaps they display (since the Sprites are always visible in my app). So, the Bitmaps cannot be garbage collected. The Bitmaps rely upon BitmapData objects for their data, so we can't get rid of them. (Up until this point it's all pretty straightforward).
Here's where I'm unsure of what's going on:
Does a BitmapData have a reference to the data loaded by the Loader? In other words, is BitmapData essentially just a wrapper that has a reference to loader.content, or is the data copied from loader.content to BitmapData?
If a reference is maintained, then I don't get anything by garbage collecting my loaders...
Thoughts?
Using AMF a bit with third party products has lead me to believe the Loader class attempts to instantiate a new class of the given content type (in this case it would be a Bitmap class instance). You are probably constructing a new BitmapData object from your Bitmap instance. From that I would assume that the Loader instance references the Bitmap instance, and in your case your code also references the Bitmap instance. Unless at some point you are calling BitmapData.clone().
There are also a couple of ways to force GC. Force Garbage Collection in AS3?
You may find it useful to attach some arbitrarily large object to something, then force the GC to see if that thing is getting cleaned up or floating around. If you are using Windows something like procmon (http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx) is more helpful than task manager for doing this kind of external inspection.
This of course is a bit trial and error but for lack of something like Visual VM (https://visualvm.dev.java.net/) we are kind of screwed in the Flash world.
It's a good question, but to the best of my knowledge, the answer is no -- neither Bitmap nor BitmapData objects possess references to the loaders that load them, so you can safely use them without concern for their preventing your Loaders from being collected.
If you want to make absolutely sure, though, use the clone() method of the BitmapData class:
clone()
Returns a new BitmapData object that
is a clone of the original instance
with an exact copy of the contained
bitmap.
For example:
private function onCreationComplete():void
{
var urlRequest:URLRequest = new URLRequest("MyPhoto.jpg");
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loader_complete, false, 0, true);
loader.load(urlRequest);
}
private function loader_complete(event:Event):void
{
var img1:Image = new Image();
img1.source = Bitmap(event.target.content);
addChild(img1);
var img2:Image = new Image();
img2.source = new Bitmap(event.target.content.bitmapData.clone());
addChild(img2);
}
Here, img1's source is a Bitmap cast explicitly from the BitmapData object returned by the loader. (If you examine the references in FlexBuilder, you'll see they are identical.) But img2's source is a clone -- new bunch of bytes, new object, new reference.
Hope that helps explain things. The more likely culprits responsible for keeping objects from being garbage collected, though, are usually event handlers. That's why I set the useWeakReference flag (see above) when setting up my listeners, pretty much exclusively, unless I have good reason not to:
useWeakReference:Boolean (default =
false) — Determines whether the
reference to the listener is strong or
weak. A strong reference (the default)
prevents your listener from being
garbage-collected. A weak reference
does not.
you may set a variable in the complete listener that stores the bitmap and then destroy the object later
public function COMPLETEListener(e:Event){
myBitmap = e.target.loader.content;
}
public function destroy(){
if(myBitmap is Bitmap){
myBitmap.bitmapData.dispose();
}
}
works fine for me load some big image and see the difference in the taskmanager

Resources