Before this post check: When simple overriding is not possible!
Here I will show how to override private functions for the Flex framework classes. If you want the DataGrid to have fix column ratios, that will never change try this.
The problem is the DataGridColumn width property. It is not simple a width property.
The documentation says: DataGrid will not always honor the width of the columns if the total width of the columns is too small or too large for the displayable area.(DataGridColumn : width property)
So as I see it: It will take the values first rather as a ratio. If you set 3 columns like 30,60,10 pixels width, it will result in columns as 30,60,10 percent of the width of the datagrid.
But when you start to resize it the ratio will disapear. After some resizes of the datagrid you will see that the columns will likely to be the same size at the end. (I think that this is a bug.)
Code: (I used the same code for all the examples but I switched off my solution to get the default behavior when it was needed)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | <?xml version="1.0"?> <!-- DataGrid control example. --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:gridOld="mx.controls.*" xmlns:gridNew="*" horizontalScrollPolicy="off" verticalScrollPolicy="off" width="500" height="220"> <mx:XMLList id="employees"> <employee> <name>Christina Coenraets</name> <phone>555-219-2270</phone> <email>ccoenraets@fictitious.com</email> <active>true</active> </employee> <employee> <name>Joanne Wall</name> <phone>555-219-2012</phone> <email>jwall@fictitious.com</email> <active>true</active> </employee> <employee> <name>Maurice Smith</name> <phone>555-219-2012</phone> <email>maurice@fictitious.com</email> <active>false</active> </employee> <employee> <name>Mary Jones</name> <phone>555-219-2000</phone> <email>mjones@fictitious.com</email> <active>true</active> </employee> </mx:XMLList> <mx:Script> <![CDATA[ [Bindable] private var startSize:Number=300;//change this startSize, and recompile to see the changes ]]> </mx:Script> <mx:Style> DataGrid { alternatingItemColors: #006699, #006655; } </mx:Style> <mx:Label text="datagrid startSize: {startSize}"/> <gridNew:EditedDatagrid headerHeight="0" showHeaders="false" id="dg" width="{startSize}" height="104" rowCount="5" dataProvider="{employees}"> <gridNew:columns> <mx:DataGridColumn dataField="name" headerText="Name" width="30"/> <mx:DataGridColumn dataField="phone" headerText="Phone" width="60"/> <mx:DataGridColumn dataField="email" headerText="Email" width="10"/> </gridNew:columns> </gridNew:EditedDatagrid > <mx:Text text="Change the size with this slider 10-20 times to see what I am talking about." height="33" width="231"/> <mx:HSlider value="{startSize}" width="400" minimum="{this.width/2}" maximum="{this.width}" snapInterval="1" enabled="true" change="dg.width=slider.value;" id="slider" liveDragging="true"/> </mx:Application> |
The first build with datagrid width 300.(default datagrid behavior, watch the ratios on creation and after resizes)
The first build with datagrid width 500. (default datagrid behavior, watch the ratios on creation and after resizes)
You can see the ratios changing! And the columns surely don’t have the good widths.
I decided to make the ratio always the same.(You could fix the column sizes too, but you may not see some columns if the datagrid is small. Fixing size is not the best thing to do.)
I don’t know if it can be done other way but it works this way for sure.
One function „calculateColumnSizes” was made protected in the DataGrid class (this is the original DataGrid made by Adobe) so EditedDatagrid class can override it.
Code: (EditedDatagrid overrides the calculateColumnSizes function. In the DataGrid I just changed private to protected. You can download all the files.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | package { import mx.controls.DataGrid; import mx.controls.dataGridClasses.DataGridColumn; import mx.core.mx_internal; use namespace mx_internal; public class EditedDatagrid extends DataGrid{ public function EditedDatagrid() { super(); } private var firstRun:Boolean=true; private var ratioSizes:Array; protected override function calculateColumnSizes():void{ var n:int = visibleColumns.length; var i:int=0; if(firstRun){ ratioSizes=new Array(n); for (i = 0; i < n; i++){ ratioSizes[i]=(visibleColumns[i] as DataGridColumn).width;//remenber the widths before calling calculateColumnSizes } firstRun=false; } /*it was needed to call this even if the result is overriden, it inicializes some things that would be missed*/ super.calculateColumnSizes(); //return; /*uncomment this "return" to see the default behaviour*/ //setting the previous ratios for the columns var newWidths:Array=new Array(n); var dataGridWidth:Number=this.width; var ratioNum:Number=sum(ratioSizes); var ratioDivider:Number=0; if(ratioNum==0){ throw new Error("cannot divide with 0"); }else{ ratioDivider=100/ratioNum; } for(i = 0; i < n-1; i++){//we dont care about the last column now (so n-1) (visibleColumns[i] as DataGridColumn).setWidth((ratioSizes[i]*ratioDivider/100)*dataGridWidth);//the previouse width will be set to it } /* The calculation is this strange because the ratios could be 40+70+90=200 % (youdont have to make the sum 100%) * ratioDivider=0.5; (100/200 100% is the max) * so for the first column ((0.5*40)/100)*width (/100 to make it percent) */ return; } private function sum(arr:Array):Number{ var sum:Number=0; for(var i:int=0;i<arr.length;i++){ if(arr[i] is Number){ sum+=arr[i]; }else{ throw new Error("something is really wrong!"); } } return sum; } } } |
The first build with datagrid width 300.(changed datagrid behavior)
The first build with datagrid width 500.(changed datagrid behavior)
Now the ratios doesn’t change!
There are usually problems when you try to hack a component, always think, how big change you need. Maybe it would be better to make your own component. This hacking works well if there is just one little problem. (It can take some time to play/debug with the code, to find the function that makes the problems.)
If you know other way to fix the column size/ratio send a comment.
I used this just as an example, how to deal with such a problems, when you have to override private functions. On the next post I will show when this won’t be enough to succeed.
Source for this project: OverrideComponents.zip
