Fit Flex datagrid to data - apache-flex

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>

Related

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.

Fill parent in Adobe Flex / MXML

I am attempting to implement a layout in Adobe Flex 4.5 / MXML where I have multiple controls in an HBox that - in total - consume all available horizontal screen estate. Some use a relative with (percentage), some an absolute width (pixels) and one is supposed to consume whatever space is still left, such as:
+----------------------+-----------------------+------+
| 35% | fill parent | 10px |
+----------------------+-----------------------+------+
How would I achieve this in Flex (is there something comparable to Android's layout_width="fillparent")?
Due to the fact that there are elements that have an absolute width I cannot easily calculate the width of the filler as a percentage a priori (as it varies with the screen width).
Setting the filler's width to 100% also does not work as this will shrink the 35% area below 35%.
Edit: Applying the updateDisplayList suggestion from www.Flextras.com's answer below yields the error "Call to a possibly undefined method updateDisplayList" at the line marked in the source excerpt below:
<?xml version="1.0"?>
<mx:HBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationPolicy="auto"
width="100%"
verticalGap="0">
[...]
<fx:Script>
<![CDATA[
[...]
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
^^^^
headerLinkBox1.width = unscaledWidth * 0.375;
headerLinkBox2.width = unscaledWidth * 0.2;
headerLinkBox3.width = unscaledWidth - headerLinkBox4.width - headerLinkBox5.width - headerLinkBox6.width;
headerLinkBox1.x = 0;
headerLinkBox2.x = headerLinkBox1.x + headerLinkBox2.width;
headerLinkBox3.x = headerLinkBox2.x + headerLinkBox3.width;
headerLinkBox4.x = headerLinkBox3.x + headerLinkBox4.width;
headerLinkBox5.x = headerLinkBox4.x + headerLinkBox5.width;
headerLinkBox6.x = headerLinkBox5.x + headerLinkBox6.width;
}
[...]
You make use of the Flex Component lifecycle and write your own layout code in updateDisplayList. Conceptually something like this:
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
super.updateDisplayList(unscaledWidth, unscaledHeight);
// size the components
comp1.width = unscaledWidth*.35
comp2.width = unscaledWidth-10-comp1.width
comp3.width = 10;
// position the components
comp1.x = 0;
comp2.x = comp1.width;
comp3.x = comp2.x + comp2.width;
}
You'll probably want to set the height of each component to, possibly using the getExplicitOrMeasuredHeight() method.

Spark TextArea or RichText autosize

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()" />

Adjusting Component size in flex

I have a viewstack with 3 items in it. Now my problem is that I want all these components to be of the same size. Its simply enough to do this manually but is there any other way of setting the size for all the components at once?
You can probably set the 'left/right/top/bottom' styles for that items.
There are (roughly) two big-time ways to go about this that I see right off the bat:
Basically you bind those components' width values to one variable, and their height values to another variable. Use the same two variables for all of your components. For example:
<mx:Script>
<![CDATA[
[Bindable]
private var m_nWidth:Number = 50;
[Bindable]
private var m_nHeight:Number = 50;
private function someFunc():void
{
m_nWidth = 100;
m_nHeight = 200;
// uic1, uic2, and uic3 are all now 100 x 200
}
]]>
</mx:Script>
<mx:ViewStack id="vs">
<mx:UIComponent id="uic1" width="{m_nWidth}" height="{m_nHeight}"/>
<mx:UIComponent id="uic2" width="{m_nWidth}" height="{m_nHeight}"/>
<mx:UIComponent id="uic3" width="{m_nWidth}" height="{m_nHeight}"/>
</mx:ViewStack>
You could also set percentage-style strings on their width and height attributes, making them scale with regards to the size of the ViewStack. For example:
<mx:Script>
<![CDATA[
private static const WIDTH:String = "50%";
private static const HEIGHT:String = "25%";
private function someFunc():void
{
vs.width = 200;
vs.height = 800;
// uic1, uic2, and uic3 are all now 100 x 200
}
]]>
</mx:Script>
<mx:ViewStack id="vs">
<mx:UIComponent id="uic1" width="{WIDTH}" height="{HEIGHT}"/>
<mx:UIComponent id="uic2" width="{WIDTH}" height="{HEIGHT}"/>
<mx:UIComponent id="uic3" width="{WIDTH}" height="{HEIGHT}"/>
</mx:ViewStack>
not sure if you already got the answer
but what i read was that you could set the main application to be 100% for bott height and width. for the viewstack you set it as 100% also. it should resize the children accordingly
or you can use actionscript percentHeight and percentWidth to set the property

Flex: Problems using scale9Grid with Image

I'm trying to create an image component that can be scaled using 9-slice scaling.
I'm 100% positive the grid rectangle is inside the image's bounds. However, the scale9Grid property seems not to affect anything.
I have tried many different things. Here is my last attempt where I try to put the image in a canvas. Any idea what I'm doing wrong?
mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="init()"
>
<mx:Script>
<![CDATA[
import mx.core.BitmapAsset;
import mx.controls.Image;
[Embed(source="assets/image.png")]
private var barImageClass:Class;
private var barImage:Image;
private function init():void
{
barImage = new Image();
barImage.addChild( new Bitmap( (new barImageClass() as BitmapAsset).bitmapData ) );
barImage.scale9Grid = new Rectangle( 120, 4, 2, 2 );
barImage.scaleX = 2;
addChild( barImage );
}
]]>
</mx:Script>
I believe you need to apply the scale9Grid to the bitmap, instead of to the sprite/movieclip it's inside of.
See this adobe doc. I think it will solve your problem. Cheers

Resources