Search This Blog

Friday, October 30, 2009

Flex: How to create a different rollover color for the header in a datagrid component?

Update 01-02-2010: Monkey patching the Flex framework does not work when RSL's are used. This is because the code of the RSL is loaded in the first frame wether the monkey patched code is instantiated in the second frame and hence does not override the RSL classes. This can be solved by instantiating the monkey patched class in a custom preloader as described here. Depending on the size of the included classes, this can invalidate the choice to use RSL's in the first place, namely to reduce application size. To include the monkey patched class in a custom preloader depends solely on the patch itself and the increased download size. These two factors should be taken into account.


In my current project I have the following requirement for styling a DataGrid component:

The roll-over color of the header should be of a different color than the roll-over color of the datagrid rows. To make things even more interesting, the roll-over color must be a gradient instead of a solid color.

Unfortunately there is no easy way to accomplish this. We can set the default background color of the header with the headerColors style, but this color is overwritten when the mouse hovers over the header. We can also disable the rollover highlighting with the useRollOver property but this does not prevent from changing the rollover color of the header! Even if we could disable the header rollover color this way, it is not a solution because we want a different rollover color for the header and the rows containing the data.

After some digging in the Flex SDK source code, the solution I came up with is to provide a customized DataGridHeader class. Please note that I customized the Flex 3.2.0 SDK because I use the 3.2.0 SDK. If you use the Flex 3.4.0 SDK you should modify the DataGridHeader class of the 3.4.0 SDK instead. To customize the DataGridHeader class I did the following:
  1. Created a mx.controls.dataGridClasses package in my own source folder
  2. Copied the DataGridHeader.as file from the Flex 3.2.0 SDK to my own mx.controls.dataGridClasses package
  3. Located the mouseOver- and mouseDownHandlers and replaced the drawHeaderIndicator method with my own drawGradientBackGround method.
  4. Added two new style attributes to the DataGridHeader class, named: startColor and endColor which defines the start- and endcolor of the gradient fill. These attributes are queried in the drawGradientBackGround method. For simplicity I did not provide default values so the default color is black.
  5. Declared the startColor and endColor attributes in css and gave them a color value.
A full working example can be downloaded from http://code.google.com/p/jc-examples/ as a zip file or from the svn repository. The following picture is taken from the sample project which demonstrates the gradient header color when the mouse is over the header. The mouse is over the name column in this case. Please note that this example uses the Flex 3.2.0 SDK.


If there are more straightforward solutions to this problem please share them.

Resources

11 comments:

Jasper Beerens said...

Great article!

Jeffrey Tummers said...

Good article, what I would like to see is some sample code in the post.

jcraane said...

I have added an explicit resources section with a link to the Google code project housing the source code and a link to the zip file containing the source code.

f said...

Thanks for introducing me to hacking of the flex framework. I spent some time looking for a solution of customizing the rollover of the datagrid header. I succeeded by using your method to re-write the drawHeaderIndicator method of the DataGridHeader class which is the method that draws the aspect of the rolled over cell in a datagrid header.

Anonymous said...

Who knows where to download XRumer 5.0 Palladium?
Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!

Unknown said...

Thanks very much for this! I'm new to Flex and was really just creating a skin for a client on a short timetable, so I didn't want to get too nitty gritty with this, but here are some improvements I'd suggest...

Instead of adding startColor and endColor to the DataGrid CSS, it would be more comprehensive and consistent with the Flex framework to add the following properties to the be acknowledged in the class specified by "headerStyleName": fillColors, fillAlphas, upSkin, overSkin, downSkin. So in other words, you'd have some CSS that looks like this:

DataGrid {
headerStyleName: dgHeader;
}
.dhHeader {
fillColors:...;
fillAlphas:...;
upSkin:...;
overSkin:...;
downSkin:...;
}

jcraane said...

Hi Stephen,

Thanks for the feedback. You're right. It is better to use the same conventions as the Flex framework itself. I will update the sample code shortly.

当当 said...

Great article, this is the only solution I found after days of searching. I just wondering is that hard for adobe to do the header skin?

Or they just want switch to new Spark one and totally drop halo.

Unknown said...

Can any body plz help me out .... I want to change the cursor style of datagrid while mouse moving over datagrid conditionally.. like for one row iant to shos hand cursor for other row i don want want .. so, can anybody me in this respect??????

Marius G. said...

Hello

Maybe the following hack will help someone.
I simply wanted to remove the rollover and selection from datagrid header (flex 3).

What I made:

1) Create a new subclass of DataGridHeader and override drawHeaderIndicator and drawSelectionIndicator

package
{
import flash.display.Sprite;

import mx.controls.dataGridClasses.DataGridHeader;
import mx.controls.listClasses.IListItemRenderer;

public class MyDataGridHeader extends DataGridHeader
{
public function MyDataGridHeader()
{
super();
}

override protected function drawHeaderIndicator(indicator:Sprite, x:Number, y:Number, width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void
{

}

override protected function drawSelectionIndicator(indicator:Sprite, x:Number, y:Number, width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void
{

}
}
}

2) Create a new subclass of DataGrid - lets say MyDataGrid and in constructor do the following:

public function MyDataGrid()
{
super();
this.mx_internal::headerClass = MyDataGridHeader;
....
}

This will force DataGrid to use your DataGridHeader.

Gaga said...

This is just awesome... except that it doesn't work for an AdvancedDataGrid !!! Aaaaargh :( Does any one has a clue how to solve that !?