Flex, AS3: Bind Width and Height of Component - actionscript-3

<forms:InfoClass xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:forms="ph.com.alliance.iportfolio.forms.*"
xmlns:ip="ph.com.alliance.iportfolio.controls.*"
styleName="info" width="{mWidth}" height="{mHeight}">
InfoClass.as:
[Bindable] protected var mWidth:Number = 400;
[Bindable] protected var mHeight:Number = 200;
I set the container width and height using Bindable, now the problem is that when I change the value of the variables on initParam, it's not reflecting on the container.
Is there anyway that I can change this variable on initParam()?
Tried it, but the width and height are still not reflected, I only get the default values. The thing is all the other binded variables are working just fine. So my question is: Is this even doable? If it is, how can I do this?
Already browsed the net for any workaround, just not sure what to search.. Any ideas?

Related

In AS3/MXML, why does binding a component's height to height / 2 work better than binding it to 50%?

Take the following AS3/MXML code:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" xmlns="*"
backgroundColor="#000000" showStatusBar="false" width="400" height="400"
minWidth="0" minHeight="0">
<s:Rect width="50%" height="50%">
<s:fill>
<s:SolidColor color="#0000FF"/>
</s:fill>
</s:Rect>
</s:WindowedApplication>
This mostly works. As I increase or decrease the size of the program, the Rect's size will scale to be 50% of the width and height of the WindowedApplication. But as I keep decreasing the window's height, the scaling down stops several pixels short of 0. This is as small as I can get the Rect to be along the y-axis:
After it gets to this point, even if I keep decreasing the size of the WindowedApplication, nothing happens. The Rect stays at exactly the same height until I start increasing the window's size again. What's more is that the Rect is 12 pixels in height, which is a pretty arbitrary number for it to be stopping on.
However if I change:
<s:Rect width="50%" height="50%">
to:
<s:Rect width="{width / 2}" height="{height / 2}">
the problem magically goes away:
The WindowedApplication's height is 5, and the Rect's height is about "two-and-a-half".
Why is there a distinction like this? In the previous example, I did try increasing, then decreasing the size again a few times, even slowly, but it always got stuck in the same spot. Thanks!
There are actually a few separate properties in play here:
height
percentHeight
explicitHeight
height is really just some smoke and mirrors behind percentHeight and explicitHeight.
In the first approach, even though you are specifying the height property as a percent in MXML; the Flex Compiler does some magic behind the scenes to check for the percent character '%' and set the percentHeight property instead of width.
Since no explicit height is given when setting the percent height; the s:Rect's validateSize() method should execute. This method seems like a parallel to the measure() method of the Flex Component lifeCycle.
The validateSize() method does some checking against the explicitMinHeight property
if (!isNaN(explicitMinHeight) && measuredHeight < explicitMinHeight)
measuredHeight = explicitMinHeight;
So, in essence, there is a minimum height; which the component's height will not go lower than.
However, in your second approach, you are not specifying a percentage you are specifying an actual value. As such the explicitHeight value is set. Because an explicit height is set that is given precedence and there is no need to execute the validateSize() method. This line in the validateSize() skips it:
if (!canSkipMeasurement())
measure();
And
protected function canSkipMeasurement():Boolean
{
return !isNaN(explicitWidth) && !isNaN(explicitHeight);
}
So, hopefully that makes sense.
In summary; if you set a percent height; then Flex calculates the height and there is a minimum value. If you set an explicit height; then Flex uses that value and skips its own internal calculations.
[I only did a cursory review of the Flex framework code, so you'll have to review code to dig down deeper]

Flex 4.6 binding to Spark GridColumn width

I know Flex is full of holes, and it needs a lot of hacks to get it to work right, but I think I'm on the right path to getting it right. I will describe the problem and the solution I'm trying to implement, I hope you can point me in the right path.
What I'm trying to do is binding the width of a Spark DataGrid column to the width of a Spark Label, here is the first hole: GridColumn has a binding property "width" but it's not ready after the object creation is complete and it's only published after user interaction. So I came up with the first hack: A function that extract the column width from the DataGrid itself and it's binded to the events that are triggered when the columns are created or their sizes changed, and it works:
[Bindable(event="creationComplete")]
[Bindable(event="columnStretch")]
[Bindable(event="propertyChange")]
public function columnWidth(grid:DataGrid, column:GridColumn):int {
if(isNaN(column.width)){
if(column.grid){
return column.grid.getColumnWidth(grid.columns.getItemIndex(column));
}
}
return column.width;
}
it works to retrive the width at creation but it doesn't work for when I set the width of the column with the cursor, as any bindable property works, so the thing is like this: If I set the width of the label as such: the width is changed after user interaction but not after the grid's creation complete. If I set the width with the width is changed after the grid is complete but it won't react to user interaction...
Any help?
It looks like I ran into the same issue a while ago. And fixed it: the following approach worked fine for me. Assume you have a function that resizes your label based on a column's width:
protected function layoutTextInputs():void {
var numCols:int = dataGrid.columns.length;
var w:Number = 0;
for (var i:int=1; i<numCols; i++) {
var header:Rectangle = dataGrid.columnHeaderGroup.getHeaderBounds(i);
var textInput:IVisualElement = textInputs.getElementAt(i - 1);
textInput.left = header.x;
textInput.width = header.width;
}
}
In this example textInputs is a Group containing a TextInput for each column, that is positioned exactly above that column and is equally wide.
Now you want to call this function every time the user resizes a column, so you do this:
dataGrid.columnHeaderGroup.addEventListener(
GridEvent.SEPARATOR_MOUSE_DRAG, onHeaderResize);
dataGrid.columnHeaderGroup.addEventListener(
GridEvent.SEPARATOR_MOUSE_UP, onHeaderResize);
private function onHeaderResize(event:GridEvent):void {
layoutTextInputs();
}
But unfortunately this does not execute the method on initialization, nor when the screen is redrawn in any way that changes the column's widths in any other way than through user interaction. Luckily this is easily fixed:
override protected function updateDisplayList(
unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
layoutTextInputs();
}
Edit: a note on the 'holes' in Flex.
GridColumn is not a visual component. It is a presentation model that instructs the grid layout how to render its (actual) columns. So you must interpret its width property as such an instruction and not as an actual value of the column's width.
By default a column's width is determined based on its contents and the available space. The width property instructs the grid layout to use a custom amount of pixels instead.
I am using mx:AdvancedDataGrid. i simply assign an ID to a datagrid column. And i binded column width property with inputText as per requirement. it works for me...
for example:
<s:textInput width="{myDatagridColumnID.width - 10}" />
I am working in Flash Builder 4.6.

How to add movieclip inside textfield

I would like to add a movieclip to a textfield. The objective is to be able to scroll the movie clip, since the uiscrollbar only works for textfield, i think my solution to scrolling the movie clip is to put it inside a textfield.
I have tried something like:
myText.addChild(myClip);
but failed with error: 1061: Call to a possibly undefined method addChild through a reference with static type flash.text:TextField.
The problem is that a TextField is not a DisplayObjectContainer, so you can't add children.
(The good news is that there are a number of alternate solutions you can find through Google)
You won't be able to add it to a textfield and I'm not exactly sure what you're mean by "scrolling the movie clip" but assuming you have a movieclip that is larger than the area you want to display it, something like this might work:
<s:Group>
<s:Scroller>
<mx:SWFLoader source="#Embed(source='movieclip.swf')"/>
</s:Scroller>
</s:Group>
Sorry if this is a bit of a thread-jack, but I recently had a situation where I needed this type of functionality. And while I'm sure you no longer need an answer to this, I hope that the solution that I came up with will help someone else.
Dear god, why would someone do this?!
In my particular case, I had an extremely long textfield that needed to scroll. In my experience, scrolling by moving the movieclip vertially is unreliable when dealing with extremely long textfields which necessitated that I use the Adobe/Flash uiscrollbar-esk method of adjusting the scrollV of the text field.
This was further complicated by the need for both in-line images which pulled from the library (as opposed to an external source) as well as a black-box border around a section of the text, both of which needed to scroll along with the text.
In a nutshell, one would probably only need to do something like this for a completely self contained swf and under extenuating circumstances (like pharma banners).
Inserting Images From Library:
To accomplish this you need to create a movieclip from an image in the library and export that movieclip for Actionscript. Then, in your code, add something like this:
//This is a string from your textfield that you will replace with an image
var matchForImageSplit:String = 'IMAGE 1 GOES HERE';
//This is the code to replace the above string
//Here, "Image1" is the class name of the exported MovieClip
var imageToAdd:String = '<img src="Image1" />';
my_text.htmlText = my_text.htmlText.split(matchForImageSplit).join(imageToAdd);
Adding the black-box border around text:
This was a bit more tricky. What I had to do was create a MovieClip with a border at the size I needed and give it a name. Then I positioned it behind the text where it was supposed to go, and enclose all of that in a parent_mc movieclip.
I then had to code the box to move along with the scrolling. The below is specific my project, but this is the gist of it:
//THIS CODE IS NON-FUNCTIONAL AND SHOULD ONLY BE USED AS A REFERENCE
//Redundant - just making the example more clear.
var my_text:TextField = parent_mc.my_text;
var borderBox:Sprite = parent_mc.borderBox;
//Vars for calculating position and movement
var borderBoxStartY:Number = borderBox.y;
var incrementRate:Number = my_text.textHeight/my_text.numLines;
var sPos:Number;
var top:Number = dragger.y;
var bottom:Number = (dragger.y + track.height) - dragger.height;
var range:Number = bottom - top;
var ctrl:Number = parent_mc.y; //"parent_mc" is the parent MC that contains the textField and borderBox
function dragScroll():void {
ratio = my_text.maxScrollV/range;
sPos = (dragger.y * ratio) - ctrl;
my_text.scrollV = Math.ceil(sPos);
borderBox.y = ((borderBoxStartY + incrementRate) - (my_text.scrollV * incrementRate));
}
One caveat to note before trying all of this is that when utilizing scrollV, text is moved line-by-line and therefore does NOT scroll smoothly (as it would with position based scrolling). This can result in the scrolling looking "jerky".
EDIT:
I should also note that this was all custom programmed and does not actually utilize the scrollPane/uiscrollbar components, but behaves in the same fashion.

simple drawing does not get display using Border container in Flex

just started a simple drawing tool in Flex to get used to the graphics coding in Flex. Got a problem in the beginning itself.
Here I am using Border Container as a drawing area (Flex 4) instead of Canvas and I am drawing simple dot on Mousemove event. Yep very simple basic thing. But I don't see the drawn dots in the border container area. But I see the Mouse Event getting fired. No Idea what am missing.
Below is my code,
<?xml version="1.0" encoding="utf-8"?>
<fx:Script>
<![CDATA[
import mx.containers.Canvas;
import mx.skins.Border;
import spark.components.BorderContainer;
protected function init():void
{
var whiteboard:BorderContainer = new BorderContainer();
whiteboard.width = 1000;
whiteboard.height = 600;
whiteboard.addEventListener
(MouseEvent.MOUSE_MOVE,whiteboard_mouseMoveHandler);
this.addElement(whiteboard);
}
protected function whiteboard_mouseMoveHandler(event:MouseEvent):void
{
var graph:Graphics =
(event.currentTarget as BorderContainer).graphics;
graph.beginFill(0x000000);
graph.drawCircle(event.localX,event.localY,3);
trace("x:"+event.localX+":y:"+event.localY);
}
]]>
</fx:Script>
The BorderContainer is most likely not expecting you to draw on it's graphics object. I haven't looked at the code for BorderContainer lately, but I recall someone else having a similar problem.
Since a BorderContainer draws a border around it's contents, it's most likely using it's graphicsobject to draw that border. So you shouldn't try to use the graphics property of the border container to draw on.
Instead, add a UIComponent or some other Flex object to the border container, and then draw your graphics on that object.
Use a skin and draw in the skin. That's the whole behaviour/skin separation is for.

How to increase the size of the busy cursor in flex mobile

I tried using the default busy cursor in flex 4.6 mobile. But the busy cursor is very small compared to the one available in web application. Is it possible to increase he size of the cursor. I dont want to add image instead of cursor.Any ideas??
Or atleast is it possible to use the busy indicator component instead of the normal busu cursor?
Generally I stay away from the busy cursor for several reasons, including the fact that it is so small on mobile apps. The busy indicator is very easy to use and can be positioned and sized how you like:
<s:BusyIndicator id="myBusyIndicator" width="100" height="100" verticalCenter="0" horizontalCenter="0" visible="false"/>
Then, when you want to show it, set the visible property to true. For instance, if you are using a httpService you could do the below:
private function myResultHandler(e:ResultEvent):void
{
myBusyIndicator.visible = false;
//handle data results
}
private function myFaultHandler(e:FaultEvent):void
{
myBusyIndicator.visible = false;
//handle fault results
}
<s:HTTPService id="myHttpService" result="myResultHandler(event)" fault="myFaultHandler(event)" invoke="myBusyIndicator.visible = true"/>