Flex3: How to "Re-load" A Component - apache-flex

How do I, in effect, "reset" a component in order to have it look the the way it did when it first loaded. For example, I've got 3 buttons in an HBox. They start as red, visible, and have a label. I then programmatically make different changes to them-- change the color of some of them, change the visibility of some of them, etc.
I then need to "reload" this HBox, have it revert back to the way it looked at the start. Is there an easy way to do this? (I have a lot of components that need to be changed).
<mx:HBox>
<mx:Button id="button1"
label="button1"
fillColors="[red, red]"
toggle="true" click="myClickHandler"/>
<mx:Button id="button2"
label="button1"
fillColors="[red, red]"
toggle="true" click="myClickHandler"/>
<mx:Button id="button3"
label="button1"
fillColors="[red, red]"
toggle="true" click="myClickHandler"/>
</mx:HBox>
If you have a suggestion, please let me know. Thank you.
-Laxmidi

You are already problematically changing this code at runtime. Just write a method to change it back to it's default state. That is probably what I'd do.
Alternately, if this is an encapsulated component, you could always remove it with removeChild, create another instance, and put that new one in the same place.
Per comments, here is some psuedo code for looping over children of a component and changing properties:
for (var i : int =0; i<hBox.numChildren; i++){
var child : UIComponent = hBox.getChildAt(i);
child.setStyle('style','defaultValue');
child.property = 'default value'
}

<mx:Application>
<mx:Script>
private function onColorChange():void
{
can.removeAllChildren();
var loader:Loader = new Loader();
loader.load(new URLRequest('assets/images/logo/1.png'));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onComplete);
/* image= new Image();
image.source = "assets/images/logo/1.jpg";
image.setStyle('horizontalCenter','0');
image.setStyle('verticalCenter','0'); */
//can.addChild(image);
txt= new Text();
txt.text = "Ankur sharma";
txt.styleName = "font";
txt.setStyle('fontFamily','Anime Ace');
txt.rotation = -10;
can.addChild(txt);
can.mask = txt;
//applyFilter(CC.uint2rgb(cp.selectedColor));
}
private function onComplete(event:Event):void
{
rect = new Rectangle();
rect = txt.getBounds(can);
can.graphics.clear();
can.graphics.beginBitmapFill(event.currentTarget.content.bitmapData);
can.graphics.drawRect(rect.x,rect.y,rect.width,rect.height);
can.graphics.endFill();
}
</mx:Script>
<mx:ColorPicker id="cp" change="onColorChange()"/>
<mx:Canvas id="can" height="100%" horizontalCenter="0" verticalCenter="0" borderStyle="solid" borderColor="#CCCCCC" borderThickness="5">
<mx:Image source="assets/images/logo/1.png" horizontalCenter="0" verticalCenter="0"/>
<mx:Text text="Ankur Sharma" styleName="font" rotation="-10"/>
</mx:Canvas>
<mx:Style source="style.css"/>
</mx:Application>
in this example, wht i m doin is i m removing all children in ma canvas(id=can) amd then then makeing n e changes, to exizting components and then adding thm back to the canvas,
this program is of masking n e ways, my canvas has two children, and i m putting ma text as a mask over the canvas, and i am filling the canva with bitmap image, thats it
i hop it hepls

Related

How to splice 2 mx canvas objects with repeat-x backgrounds?

I have 2 canvas objects that both contain a tiling image. My client recently requested that both the images be able to appear at the same time. I simply allowed them to be both enabled at the same time thinking they would tile appropriately but they do not.
After some careful thought I realized this is because they are of varying width so although my tiling image is 7 pixels in width, it may not always end at 7 pixels thus causing it to not appear to tile cleanly.
I can't just lop off the remainders because the imagery is being used to assess quantities of items (without going into too much detail) and having item 1 with 97 quantity next to item 2 with 200 quantity on one row compared to row 2 with item 1 having 100 quantity and item 2 having 300 quantity will show up strange to the end-user.
Does anyone know of how I could get started with maybe splicing the two canvas objects together or rather using 1 canvas object and then using BOTH background images and setting a percentWidth or something that the other one comes into affect?
You can use the copyPixels() method of the BitmapData class to achieve this sort of result. To do this, you need to load each image with a Loader. When the images are loaded, you have two Bitmap objects. From there, you access the corresponding BitmapData for each Bitmap and can splice them together.
After the splice, you create a new Bitmap object from the combined BitmapData. Then you feed the combined Bitmap to some other component. Unfortunately, a Canvas won't accept a Bitmap for its backgroundImage style. But you can add the combined Bitmap to a UIComponent or set it as the source of an Image component.
Finally, add either the UIComponent or Image to a Canvas. Since you can layer things on the Canvas, you effectively have a background image as long as place (and leave) the combined image at index 0 of the Canvas.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
minWidth="955" minHeight="600"
creationComplete="onCreationComplete()">
<mx:Script>
<![CDATA[
import mx.containers.Canvas;
import mx.controls.Image;
import mx.core.UIComponent;
import mx.events.FlexEvent;
private var loader1:Loader;
private var loader2:Loader;
private var bitmap1:BitmapData;
private var bitmap2:BitmapData;
protected function onCreationComplete():void
{
loader1 = new Loader();
loader1.load(new URLRequest("Android_Robot_100.png"));
loader1.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoader1Complete, false,0,true);
loader2 = new Loader();
loader2.load(new URLRequest("rails.png"));
loader2.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoader2Complete, false,0,true);
}
protected function onLoader1Complete(event:Event):void
{
bitmap1 = (loader1.content as Bitmap).bitmapData;
if (bitmap1 && bitmap2)
copyPixels();
}
private function onLoader2Complete(event:Event):void
{
bitmap2 = (loader2.content as Bitmap).bitmapData;
if (bitmap1 && bitmap2)
copyPixels();
}
protected function copyPixels():void
{
// false = non-transparent background
var combined:BitmapData = new BitmapData(200,200, false);
var sourceRect1:Rectangle = new Rectangle(0,0,bitmap1.width, bitmap1.height);
var sourceRect2:Rectangle = new Rectangle(0,0,bitmap2.width, bitmap2.height);
combined.copyPixels(bitmap1, sourceRect1, new Point(0,0));
combined.copyPixels(bitmap2, sourceRect2, new Point(bitmap1.width, 0));
var result:Bitmap = new Bitmap(combined);
var image:Image = new Image();
image.source = result;
var canvas:Canvas = new Canvas();
canvas.addChildAt(image, 0);
addChild(canvas);
// as an alternative, just add the bitmap to a UIComponent
// note you can't do this and the above at the same time,
// becuase the 'result` Bitmap can only be the child of one
// object, adding it to one thing removes it from the other...
// var uic:UIComponent = new UIComponent();
// uic.addChild(result);
// addChild(uic);
}
]]>
</mx:Script>
</mx:Application>
Ultimately I was overcomplicating it. I simply did this with masking like...
<mx:Canvas width="100%" height="100%">
<mx:Image id="myFirstUnrelatedImage" width="50%" height="65%" maintainAspectRatio="false"
verticalCenter="0" left="3"
source="#Embed('../assets/image1.png')" visible="true"/>
<!-- not sure why borderStyle here is required but it won't show up without? -->
<mx:Canvas id="image1mask" width="30%" height="94%"
borderStyle="none" visible="false"/>
<mx:Canvas id="image1" width="100%" height="100%"
minWidth="0" styleName="myStyle"
mask="{image1mask}"/>
<!-- not sure why borderStyle here is required but it won't show up without? -->
<mx:Canvas id="image2mask" width="20%" height="94%"
right="0" borderStyle="none" visible="false"
includeInLayout="false"/>
<mx:Canvas id="image2" width="100%" height="100%"
minWidth="0" styleName="myStyle2"
mask="{image2mask}"/>
</mx:Canvas>
Where my styles were controlling the backgroundImage and backgroundRepeat properties in css.

How to add an icon to an AdvancedDataGrid column header and keep word wrap feature for the text

As stated, I'm trying to obtain column headers consisting of an icon and wrappable text in a flex AdvancedDataGrid.
(EDIT: I forgot to mention an important part of the context: the columns are added dynamically, in actionscript. This apparently changes the behavior.)
I've tried using a custom mxml headerRenderer, like so:
<mx:headerRenderer>
<fx:Component>
<mx:HBox width="100%"
height="100%"
verticalAlign="middle">
<mx:Image source="<image_url>"
width="10%"
height="100%"/>
<mx:Text text="{data.headerText}"
width="90%"
height="100%"/>
</mx:HBox>
</fx:Component>
</mx:headerRenderer>
but for some reason, the text here is truncated instead of wrapped (it works outside of a renderer).
I've also tried creating a subclass of AdvancedDataGridHeaderRenderer and overriding createChildren to add the icon:
override protected function createChildren():void
{
var icon:Image = new Image();
icon.source = <image_url>;
icon.width = 16;
icon.height = 16;
addChild(icon);
super.createChildren();
}
but then, the icon and the text get superimposed.
I'm out of ideas on this. Anyone else?
It worked for me when I removed the height="100%" attribute from mx:Text in your headerRenderer.
UPDATE: it only works like this when I manually stretch the AdvancedDataGrid component. I'll look into how to make it work unconditionally.
When the height of the Text component was set to 100%, it was constrained to its parent HBox's height. Therefore when a word was wrapped and moved to the next line, it wasn't visible because the height of the Text component didn't allow for it to be visible.
If you remove this constraint, Text component's height will be determined dynamically based on its contents, as will headerRenderer's. Also add minHeight to your Text so that it is visible when it's loaded.
Here's the code (I also removed scrollbars because they were showing during resize):
<mx:headerRenderer>
<fx:Component>
<mx:HBox width="100%"
height="100%"
verticalAlign="middle"
horizontalScrollPolicy="off"
verticalScrollPolicy="off">
<mx:Image source="<image_url>"
width="10%"
height="100%"/>
<mx:Text text="{data.headerText}"
width="90%"
minHeight="20"/>
</mx:HBox>
</fx:Component>
</mx:headerRenderer>
In case anyone is interested in how to do this with dynamically created columns, a combination of Hunternif's code for the renderer and some added code on column creation worked for me:
The columns need to have fixed widths and need to be invalidated to inform the AdvancedDataGrid that it needs to rerender:
var cols:Array = [];
for each (...) {
var column:AdvancedDataGridColumn = new AdvancedDataGridColumn();
...
// Fix the width of created columns
column.width = 150;
cols.push(column);
}
grid.columns = cols;
// Invalidate columns so that sizes are recalculated
grid.mx_internal::columnsInvalid = true;
// Take changes into account
grid.validateNow();

Flex DividedBox children are displayed outside

I am using a DividedBox in Flex which contains only a datagrid at first. When I click on an Item on the Datagrid, a second element with a width of 0% (Spark Group) is added to the divided box to display an image.
The thing is, when the second element is added to the DividedBox, the image is partially displayed outside the DividedBox, and I don't want to have this behavior.
Here is the interesting code :
<mx:DividedBox direction="horizontal" id="divider" borderColor="red" borderStyle="solid" borderVisible="true" right="10" left="10" top="10" bottom="10">
<s:Group width="100%" height="100%">
<!--datagrid-->
</s:Group>
</mx:DividedBox>
And here is the piece of code that adds the second child of the dividedBox (simplified code) :
private var _pdf_preview:Group = new Group();
[Bindable]
[Embed(source="assets/image/llama.jpg")]
private var imgClass:Class;
protected function itemOnClickHandler(event:MouseEvent):void
{
_pdf_preview = new Group();
var img:Image = new Image();
img.source = imgClass;
_pdf_preview.addElement(img);
_pdf_preview.percentWidth = 0;
divider.addElement(_pdf_preview);
}
And here is a screen of the problem (Btw, don't notice my skills on Gimp :) ). As a new user I can't bind images to my post : screen showing my problem the red border show the limits of the dividedBox
Thank you.
I hope there are not too much fault, english is not my native language. Sorry for any english mistakes.
PS : I couldn't add the "DividedBox" tags because it was not existing before, and I'm a "new user" so I can't create new tags.
You can use the clipContent property to cut off the image at the edge of the DividedBox:
<mx:DividedBox clipContent="true" />
When using Spark containers, clipAndEnableScrolling is the property you need to achieve the same goal.
I would also like to note that you usually don't require to dynamically add components through ActionScript. You can use 'states' instead. For example:
<s:states>
<s:State name="normal" />
<s:State name="image" />
</s:states>
<mx:DividedBox clipContent="true">
<s:DataGrid />
<s:Image includeIn="image" />
</mx:DividedBox>
Now all you need to do to show the Image, is set the currentState to image.

In flex, how to get coordinates when using VBox for stacking up components?

In flex, I am using VBox & HBox to stack components. When I try to get x,y coordinate of a component, I always get 0. If I specify coordinate like mx:VBox x="120", then I get the value.
How can I get the coordinate without explicitly stating it.
You can translate the coordinates relatively to the stage. Check out the code below:
var box:VBox = new VBox;
var child:DisplayObject = new DisplayObject;
box.addChild(child);
child.addEventListener(FlexEvent.UPDATE_COMPLETE, updateCompleteHandler);
...
private function updateCompleteHandler(fe:FlexEvent):void{
// find global coordinates
var globalCoords:Point = child.localToGlobal(new Point(0,0));
// coordsInBox is what you are looking for
var coordsInBox:Point = box.globalToLocal(globalCoords);
}
The point is to use localToGlobal for the child components and then globalToLocal to translate the global coordinates so that they were expressed relatively to the box container.
Please notice, that the coordinates won't be processed until UPDATE_COMPLETE is called by the child object.
The X and Y values of a component are always relative to the component's parent. directionsHelp.x and directionsHelp.y will both return the position relative to the VBox containing them which, unless you explicitly set the values or insert other components around it, will be 0 by default.
The thing to remember about localToGlobal() is that you must call it from the child. If you have an Application and you just call localToGlobal( new Point(child.x, child.y) ), it will try to return the given point within the Application relative to the stage (because you haven't specified what "local" is), which will therefore conduct no transformations, and it will therefore stay equal to (0, 0).
If however you call child.localToGlobal( new Point(child.x, child.y) ), it will return the value of the child's position relative to the stage, transforming the given point by however much the child is offset on the stage.
Here's a quick app to demonstrate:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#FFFFFF">
<mx:Script>
<![CDATA[
private function updateCoords():void
{
var point:Point = new Point(directionsHelp.x, directionsHelp.y);
point = directionsHelp.localToGlobal(point);
directionsHelp.text = "My stage coordinates are ("+point.x+", "+point.y+")";
}
]]>
</mx:Script>
<mx:VBox>
<mx:Box height="100" width="100" borderStyle="solid" borderColor="#000000"
horizontalAlign="center" verticalAlign="middle">
<mx:Label text="100 x 100" />
</mx:Box>
<mx:VBox>
<mx:Text id="directionsHelp" color="#4FA4CD" fontSize="8" fontWeight="bold"
text="Click the button to display my position on the stage." />
<mx:Button label="Get Position" click="updateCoords()" />
</mx:VBox>
</mx:VBox>
</mx:Application>

Flex container transform matrix problems

I have a Box container that has a label element inside it. When the box is transformed using a Matrix the label element is not visible anymore. How do I make the elements visible?
<mx:Script>
<![CDATA[
private function onBoxClick(event:MouseEvent):void
{
var transformMatrix:Matrix = this.box.transform.matrix;
transformMatrix.c = Math.PI * 2 * -15 / 360;;
this.box.transform.matrix = transformMatrix;
}
]]>
</mx:Script>
<mx:HBox id="box"
x="100" y="100"
width="100" height="100"
backgroundColor="0x000000"
click="onBoxClick(event)">
<mx:Label id="textLabel" text="This is a test" color="#FFFFFF" visible="true"/>
</mx:HBox>
I'm guessing the TextField inside the Label component doesn't have the font embedded. If you plan to use .rotation or .alpha on a dynamic text you must embed the font.
You can easily test this with a regular TextField:
var t:TextField = new TextField();
t.defaultTextFormat = new TextFormat('Verdana',12,0x000000);
t.embedFonts = true;
t.rotation = 10;
t.text = 'rotated';
addChild(t);
That is assuming you have the Verdana font embedded in this example. If you comment out the 3rd line you will see the text disappear.

Resources