Flex 4.6 binding to Spark GridColumn width - actionscript-3

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.

Related

Change or Set Cell Class Dynamically in Ag Grid

I have a Div whose size can vary (only div resize) based on user action (small & large view) and this div contain ag-grid.
Initially div/grid load in compress size so I have used class according to that like (small font-size, height, padding etc.) to remove scrolls
but I want when user enlarge the div size the class will swap with another class (large font-size, height etc.) but I couldn't find any grid api or method to set cellClass and headerClass dynamically.
One more thing can I update that in gridOptions and load grid according to new option.
Add a listener to gridSizeChanged event. In the listener, check for the window/div size and apply CSS classes accordingly.
var gridOptions = {
...
onGridSizeChanged: onGridSizeChanged
};
function onGridSizeChanged(params) {
let newClass = (css class for new width)
gridOptions.api.getColumnDef(colId).headerClass = newClass;
gridOptions.api.refreshHeader()
}

LibGDX - Get width of label cell in ImageTextButton

I have ImageTextButtons within a container Table. I would like to dynamically change the width of this table and have the ImageTextButtons respond in a particular manner. What I would like them to do is fade in the label text depending on the percentage of the text shown.
I believe I am dynamically setting the table width and contents correctly. As per the LibGDX documents we should not explicitly set the widgets dimensions, but the table (container) cell dimensions. So for testing, I have a simple clickListener on what of the buttons like this;
button.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
super.clicked(event, x, y);
float max = container.getCell(button).getMaxWidth();
container.getCell(button).width(max*0.9f);
container.invalidate();
}
});
This works fine, I click it and the cell (and the widget) shrink 90% each time.
For the next step, I thought it would be as simple as this, in my custom ImageTextButton's draw() method;
glyphWidth = getLabel().getGlyphLayout().width;
labelCellWidth = getLabelCell().getMinWidth(); ///<--problem here
float glyphOpacityMultiplier = MathUtils.clamp(labelCellWidth/glyphWidth, 0f, 1f);
origLabelColor = getLabel().getColor().cpy();
newLabelColor = origLabelColor.cpy();
newLabelColor = new Color(newLabelColor.r, newLabelColor.g, newLabelColor.b, newLabelColor.a*glyphOpacityMultiplier);
getLabel().setColor(newLabelColor);
super.draw(batch, parentAlpha);
getLabel().setColor(origLabelColor);
This all works, except for the fact I can't find any method to give me with actual width of the Cell that contains the label. Since the ImageTextButton itself is also a Table, I tried to do button.invalidate() in the ClickListener too but it didn't help. These are the methods I have tried so far;
getLabelCell().getMinWidth();
getLabelCell().getMaxWidth();
getLabelCell().getPrefWidth();
getLabelCell().getActorWidth();
getLabelCell().getSpaceLeft();
getLabelCell().getSpaceRight();
None of them seem to update and give me the correct size, however I know something is working somewhere because I turned on "setClip(true)" on the ImageTextButton, and the label text is successfully being clipped within the boundaries of the NinePatch background when it is resized. So how do I get the correct size?
Any help is greatly appreciated!
Oops.. solved it. I thought the cell containing the label would be offset and sized by the NinePatch background but its not, it is full size but has padding. Therefore the answer is;
labelCellWidth = getWidth()-getPadLeft()-getPadRight();

AS3: Who should I layout first the parent or the children?

I am building large application in Starling and one of my main problems is who should I layout first: the parent or the children?
What is the default behavior in starling and also in flash:
By default Sprite will get his size based on his children after they have been added to stage.
What if I want to layout the children based on the parent? For example: What if I want to set one of the children to be at position of 20 pixels from the bottom, like bottom menu?
In this case I should:
Add the children
Determine their sizes. If you are building your application cross platform, you need to support many screens, and many times you come to have complicate logic for calculating the scale percentage of your components, which is their size.
Determine your size and layout yourself.
now the bottom menu could be layout at 20 pixels from the bottom. Also it doesn't matter if you place this logic inside the bottom menu or it's parent.
But this not always the case, sometimes you want to layout the parent based on his children. A common example if one of the children is the parent background. In this case you should:
Add the background.
Determinate background size and layout it.
Now you can layout the parent.
But what if I got both of the cases? If one of parent children is background and the other is bottom menu? What if the bottom menu got his own background and other children that need to be layouted base on the parent?
What solution can be used so I will not get lost inside all of this, and can Gazman SDK help here?
What you need is to create layout dependencies between all the components. Each Sprite should have an event that tells us when its layouting is complete.
Now if you have some layouting logic inside the parent that cannot start until its background child is complete layouting, you should create a dependency between the background and the parent. The parent should listen to LayoutComplete event from the background and then he can layout himself, and when he complete layouting he can dispatch LayoutComplete event, and now its child bottom menu can layout himself.
You can implement it yourself or use Gazman-SDK that do exactly that. If you choose Gazman-SDK your code will look like this:
public class ParentClass extends Group
{
private var background:Background = new Background();
private var bottomMenu:BottomMenu = new BottomMenu();
override protected function initialize():void
{
// check if not already added to stage
if(!background.parent){
addChild(background);
addChild(bottomMenu);
}
// Create dependency for background. If background have not
// been initialized yet the subscription will succeed
// And this.initialize() will be called again once
// background initialize is complete
if (subscribeForInitilize(background)){
return;
}
// do layouting logic here
}
}
public class BottomMenu extends Group
{
override protected function initialize():void
{
// Create dependency for parent. If parent have not
// been initialized yet the subscription will succeed
// And this.initialize() will be called again once
// parent initialize is complete
if (subscribeForInitilize(parent as Group)){
return;
}
// do layouting logic here
}
}

How get a string width in Libgdx?

I wonder know how to get the width of my string in pixels
BitmapFont API < 1.5.6
To mesure the width of a String you use your Font and get the bounds of the String, you are going to draw.
BitmapFont.getBounds(String str).width
BitmapFont API
You can get the height to for the right offset for drawing too. Just replace width with height.
In addition for multiline texts use getMultiLineBounds(someString).width to get the bounds.
BitmapFont API >= 1.5.6
The BitmapFont API changed in 1.5.7 so there is a different way to get the bounds now:
BitmapFont.TextBounds and getBounds are done. Instead, give the string to GlyphLayout and get the bounds using its width and height fields. You can then draw the text by passing the same GlyphLayout to BitmapFont, which means the glyphs don’t have to be laid out twice like they used to.
Source (Web archive)
Example:
GlyphLayout layout = new GlyphLayout(); //dont do this every frame! Store it as member
layout.setText("meow");
float width = layout.width;// contains the width of the current set text
float height = layout.height; // contains the height of the current set text
According to #Nates answer: https://stackoverflow.com/a/20759876/619673 calling method
BitmapFont.getBounds(String str).width
not always returns proper width! Especially when you are reusing font.
If you want draw text for example in the center of part of view port, you can avoid this problem by using another method
BitmapFont.drawWrapped(...)
Example code:
font.drawWrapped(spriteBatch, "text", x_pos, y_pos, your_area_for_text, BitmapFont.HAlignment.CENTER);
If you use skins in UI it is a hassle to find out the correct font to feed into the GlyphLayout.
In this case I use a throw away instance of Label to figure everything out for me then ask the Label for the width.
Skin skin = getMySkin();
Label cellExample = new Label("888.88888", skin);
cellExample.layout();
float cellWidth = cellExample.getWidth();
Table table = new Table(skin);
table.defaults().width(cellWidth);
// fill table width cells ...
This is not the answer if you want to position the text yourself, but it is useful to make a UI layout stable and less dependent on the actual content of the cells.

last column of spark datagrid is not resizing

i have used spark datagrid for my mobile application . my problem is last column of my spark datagrid is not resizing to the grid's width. for example, my spark datagrid's width is 500,and i have 4 columns of width size 100 each. four columns are places as per their size in the datagrid. but the last 100 pixels in datagrid looks like empty space.In advanced datagrid and mx datagrid , the columns are automatically resized to the grid's width.
please help me to achieve this, in the spark datagrid.
thanks
vengatesh
This is sprk DataGrid issue. To avoid it you need to listen event "resize" from DataGrid and in handler set last column's width to NaN.
protected function dataGridResizeHandler(event:ResizeEvent):void
{
lastColumn.width = NaN;
}
That works for me.