Spark TextArea or RichText autosize - apache-flex

I have done lots of searching on this subject, but it seems what I am finding is either out of date or just does not seem to work.
With TextFields in the past, you could set the TextField to a certain width, set wordWrap to true and you would end up with a textfield that changed height according to the text you added.
Now I am trying to do this with either the Spark TextArea or RichText.
I tried this HeightInLines = NAN, but that seems to be out of date.
I also tried this routine:
var totalHeight:uint = 10;
this.validateNow();
var noOfLines:int = this.mx_internal::getTextField().numLines;
for (var i:int = 0; i < noOfLines; i++)
{
var textLineHeight:int =
this.mx_internal::getTextField().getLineMetrics(i).height;
totalHeight += textLineHeight;
}
this.height = totalHeight;
But the mx_internal is not in the Spark components.
I am trying to do this with AS3, not MXML. If anyone has any suggestions or links that could help me figure this out using AS3, I'd really appreciate it.

Been struggling with this all afternoon. But it looks like the RichEditableText component will autosize if you set its width and leave its height undefined.

This works fine:
<?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">
<s:TextArea updateComplete="event.currentTarget.heightInLines = NaN" />
</s:Application>
Found in comments here. You can do the same in ActionScript using the same updateComplete event.

This is how I set the height of a TextArea to fit its content when used inside an ItemRenderer (e.g. for a List component):
private function onUpdateComplete( e: Event ): void
{
// autoresize the text area
if ( theText ) {
var actualNumOfLines: int = theText.textFlow.flowComposer.numLines;
theText.heightInLines = actualNumOfLines;
invalidateSize();
}
}
ItemRenderer must have this property set:
<s:ItemRenderer ... updateComplete="onUpdateComplete(event)>
Maybe the updateComplete event is not the optimal trigger for auto-resize actions but works fine for me.

You can remove scrollers from TextArea's skin and it becomes autoresizable. You can download completed skin here: http://www.yumasoft.com/node/126

Here's a solution for spark text areas (it works as mx text areas do):
var ta_height:int;
for(var i:int=0; i < StyleableTextField(myTextArea.textDisplay).numLines; i++) {
ta_height += StyleableTextField(myTextArea.textDisplay).getLineMetrics(i).height;
}
myTextArea.height = ta_height;

This seems to work for me:
<s:TextArea id="testTextArea"
change="testTextArea_changeHandler(event)"
updateComplete="testTextArea_updateCompleteHandler(event)"/>
<fx:Script>
<![CDATA[
protected function testTextArea_changeHandler(event:TextOperationEvent):void
{
testTextArea.height = RichEditableText(testTextArea.textDisplay).contentHeight + 2;
}
protected function testTextArea_updateCompleteHandler(event:FlexEvent):void
{
testTextArea.height = RichEditableText(testTextArea.textDisplay).contentHeight + 2;
}
]]>
</fx:Script>

Been doing the same head banging over that s:TextArea, and then found out that this gets the job done :
<s:RichEditableText id="txtArea" left="0" right="0" backgroundColor="#F7F2F2"
change="textChanged()" />

Related

FillColor of CheckBox in Flex 3

I have about 8 checkboxes that are created dynamically using a for loop. Each checkbox has a different color. Basically i want to change the fillColor of every checkbox (label not included) using 8 predefined colors. Here's my code.
for (var i:int=0; i <= annotatorNames.length; i++)
{
var checkbox:CheckBox = new CheckBox();
var colorIndex:int = parseInt(annotatorColours[i]) - 1;
var checkboxColor:String = UiConstants.ANNOTATOR_COLORS[colorIndex];
checkbox.label=annotatorNames[i];
checkbox.selected=true;
checkbox.setStyle("fillColors", [checkboxColor, checkboxColor, checkboxColor, checkboxColor]);
annotatorCheckboxes[i] = checkbox;
this.addChild(checkbox);
}
For some reason fillCollors does not apply and the checkbox is not styled. If i style the label it works...also pretty much any other style applies..but not fillColors. What am I doing wrong here?
The code does not have errors and colors are in the form of "0XA52A2A".
Try using a stylesheet, including something like:
CheckBox {
fillColors: #yourColor, #yourColor, #yourColor, #yourColor;
}
import it by the following statement:
<mx:Style source="yourstylesheet.css"/>
You have an issue with pieces of code that aren't in the example, i.e. the constants UiConstants.ANNOTATOR_COLORS[colorIndex]; etc
I trimmed your code to just the bare minimum to research your defect and the setting of the styles works without issue.
The following code works perfectly fine, run this and check it out:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.controls.CheckBox;
private function init() : void {
for (var i:int=0; i <= 8; i++)
{
var checkbox:CheckBox = new CheckBox();
var checkboxColor:String = 'red';
checkbox.label=i.toString();
checkbox.selected=true;
checkbox.setStyle("fillColors", [checkboxColor, checkboxColor, checkboxColor, checkboxColor]);
holder.addChild(checkbox);
}
}
]]>
</mx:Script>
<mx:HBox id="holder"/>
</mx:Application>
That should point you in the right direction...

How can I show a line under each row of text in a Spark TextArea

I'm trying to show a horizontal line under each row of text in a Spark TextArea. I want to give the text area the look of legal paper.
Ah actually ran into a similar problem in Flex 3 doing a strikeout for a disabled link-button that was part of our styles. Just checked out the code and looked on the docs for the spark label and found the function I was using from a mx label explicitly says it won't work [from measureText() in spark label]:
Measures the specified text, assuming that it is displayed in a
single-line UITextField (or UIFTETextField) using a UITextFormat
determined by the styles of this UIComponent. Does not work for Spark
components since they don't use UITextField (or UIFTETextField). To
measure text in Spark components, get the measurements of a
spark.components.Label or spark.components.RichText
So I re-figured it out:
<?xml version="1.0" encoding="utf-8"?>
<s:Label xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
override protected function updateDisplayList(unscaledWidth : Number, unscaledHeight : Number) : void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
drawLines();
}
private function drawLines() : void
{
var totalHeight : Number = 0;
for (var i : int = 0; i < mx_internal::textLines.length; i++)
{
totalHeight = mx_internal::textLines[i].y;
graphics.lineStyle(1, 0x000000);
graphics.moveTo(0, totalHeight);
graphics.lineTo(width, totalHeight);
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:Label>
Set the textDecoration style for the control.

Displaying black and red ToolTips as speech baloons

I'm porting a card game from pure Flash/AS3 to Flex 4.5:
I'm almost done, but the "speech baloons" marked by the blue color in the screenshot above are missing.
Those "speech baloons" fade in, display red (if they contain hearts or diamonds char) or black text and finally fade out.
I'm trying to implement those as mx.controls.ToolTips and have prepared a simple test case, where 3 users are represented by smiley-buttons and you can push a "Talk"-button to make them talk:
<?xml version="1.0"?>
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
width="400" height="300"
initialize="init();">
<fx:Declarations>
<s:Fade id="fadeIn" alphaFrom="0" alphaTo="1" duration="2000"/>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.managers.ToolTipManager;
private var i:uint = 0;
private function init():void {
ToolTipManager.enabled = false;
ToolTipManager.showEffect = fadeIn;
}
private function talk():void {
var str:String = 'Me plays 10' + (i % 2 ? '♥' : '♠');
// this does not make the ToolTip appear?
this['user' + (++i % 3)].toolTip = str;
// how to set color according to isRed(str)?
}
private function isRed(str:String):Boolean {
return (str.indexOf('♦') > 0 || str.indexOf('♥') > 0);
}
]]>
</fx:Script>
<s:Button id="user0" horizontalCenter="0" bottom="0" label=":-)" />
<s:Button id="user1" left="0" top="0" label=":-)" />
<s:Button id="user2" right="0" top="0" label=":-)" />
<s:Button right="0" bottom="0" label="Talk!" click="talk()" />
</s:Application>
Can anybody please give me hints?
How to make ToolTips appear at will? (and not just on mouse hover)
How to change their color (I only found how to set it once by CSS)
UPDATE:
I've tried the following
private var tip0:ToolTip;
private var tip1:ToolTip;
private var tip2:ToolTip;
private function talk():void {
var str:String = 'Me plays 10' + (++i % 2 ? '♥' : '♠');
var btn:Button = this['user' + (i % 3)];
var tip:ToolTip = this['tip' + (i % 3)];
tip = ToolTipManager.createToolTip(str, btn.x + 10, btn.y + 10, "errorTipBelow", IUIComponent(btn)) as ToolTip;
}
but this does not work too well - no effects, no disappearing (I guess I have to call destroyToolTip myself). I wonder if ToolTip can be (ab)used for my purpose of representing "speech baloons" in an elegant way at all...
Personally, I have found the tool tip system rather limiting, and any time I want to do something a bit more different, it just seems easier to implement it manually. Generally in this case I would add a PopUpAnchor control to the components that need these overlay displays. Then you have full manual control over what is shown, and exactly how it is shown.
http://blog.flexexamples.com/category/spark/popupanchor-spark/
There are quite a few ways to do this though as well as just building the tooltip component as a subclass of Group, adding it as a child, and keeping track of it.

tab index on flash movieclip in flex

I have a form that pops up in flex, it is a movieclip contained within a UIComponent. Within this movieclip are form fields.
For some reason I can't get the tab button working to be able to tab between the fields. I set up each field with a tabindex, but that doesn't work.
Is there anything else I need to do besides this? This is basically all the code I am using:
email.tabIndex = 1;
city.tabIndex = 2;
firstName.tabIndex = 3;
etc.
Is this not working because of flex? And if so, what is a workaround?
have you tried adding a new FocusManager instance to the UIComponent that contains the movieclip? I am not sure but maybe.
Also another thing I can think of could be the tabEnabled property of the form elements and the containing Objects.
Hope it gets you closer.
Good luck,
Rob
////////// UPDATE ///////////////
Unfortunately I couldn't make it work, but I send you my code, maybe you can do something with it.
I tried to add a movieclip and the textfields into it, but it's the same, no TAB at all. So I simply added the textfields to the UIComponent and set all the possible tab and focus related properties to true - no luck :(.
<?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">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.core.UIComponent;
import flash.display.MovieClip;
import flash.text.TextField;
protected function init(event:Event):void
{
var i:uint = 0;
var l:uint = 4;
while (i < l)
{
var tf:TextField = new TextField();
tf.name = "tf_" + i;
tf.width = 200;
tf.height = 21;
tf.border = true;
tf.type = "input";
tf.tabIndex = i;
tf.tabEnabled = true;
tf.text = "tabIndex = " + String(tf.tabIndex);
tf.x = 50;
tf.y = tf.height * i + 10 * i + 100;
uicomp.addChild(tf);
++i;
}
};
]]>
</fx:Script>
<mx:UIComponent hasFocusableChildren="true" tabChildren="true" tabEnabled="true" tabFocusEnabled="true" id="uicomp" width="100%" height="100%" addedToStage="init(event);" />
</s:Application>
Sorry, that's all I could do for now. If you get the answer please let me know, I am keen.
Cheers,
Rob

Fit Flex datagrid to data

I have rows of text data that can vary between 0 and 100, and all need to be visible on the screen at one time. The default behavior is fine for the grid until the rows * rowHeight > gridHeight.
Basically I need a hook into the item height, or row height to calculate it based on the height of the grid. I've set paddingTop and paddingBottom to zero, but there is still a considerable amount of white space in between rows.
My datagrid component...
<mx:DataGrid xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="OnCreationComplete()"
paddingTop="0"
paddingBottom="0"
>
<mx:Script>
<![CDATA[
private function OnCreationComplete():void
{
//setRowHeight(10);
}
override protected function setRowHeight(v:Number):void
{
super.setRowHeight(v);
}
]]>
</mx:Script>
</mx:DataGrid>
setRowHeight() helps, but the itemRender for the cell bigger than the cell, if I set the row height to something like 10.
You might want to look at the DataGrid.variableRowHeight property as, when this is set to false (the default) all rows will be the same height as the largest itemRenderer. You could also look into writing your own itemRenderer for each DataColumn.
If all you really want to do is set the row height based on the number of items in the dataProvider though, you could just set the DataGrid.rowHeight property like this (assuming your grid has a fixed height, say 100%) :
myDataGrid.dataProvider = myArray;
myGrid.rowHeight = Math.floor((myGrid.height - myGrid.headerHeight)/myArray.length);
(I'm taking the floor here because if you end up with a fractional value that rounds up, you'll need a scroll bar)
The only problem with this approach, as I think you've noticed, is that the itemRenderer might not display properly in a row that's too small. I guess you could solve this by changing the font within the renderer based on its height.
Thank you inferis, that helped me a lot. This is my final grid component. It's not really self contained because of a few call-outs, but if it helps someone else get theirs to work, great!
<?xml version="1.0" encoding="utf-8"?>
<mx:DataGrid xmlns:mx="http://www.adobe.com/2006/mxml"
paddingTop="-3"
paddingBottom="-3"
resize="OnResize(event)"
>
<mx:Script>
<![CDATA[
import mx.containers.Panel;
import mx.core.Application;
import mx.events.ResizeEvent;
protected function OnResize(event:ResizeEvent):void
{
this.invalidateDisplayList();
}
/**
* #private
* Sizes and positions the column headers, columns, and items based on the
* size of the DataGrid.
*/
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
if( this.collection.length > 0 ) // so don't divide by zero
{
var appHeight:Number = Application.application.height;
var appMinusMenuHeight:Number = appHeight - Application.application.hboxPrintBar.height;
var boxHeight:Number = Application.application.vboxViewAll.height;
if( boxHeight > 0 )
{
var gridHeight:Number = (appMinusMenuHeight - this.headerHeight) * 0.93;
var calcHeight:Number = gridHeight / this.collection.length;
var calcHeightFloor:Number = Math.floor( calcHeight );
setRowHeight( calcHeightFloor );
//var p:Panel = this.parent as Panel;
//p.title = calcHeightFloor.toString();
if( calcHeightFloor <= 10 )
this.setStyle("fontSize",calcHeightFloor);
}
}
super.updateDisplayList(unscaledWidth,unscaledHeight);
}
]]>
</mx:Script>
</mx:DataGrid>

Resources