Wednesday, February 20, 2008

Changing row background color in AdvancedDataGrid

Changing the row backgroundColor in AdvancedDataGrid to highlight few rows is easy (though not possible out of the box).

I have used a different approach than overriding the drawRowBackground function used for DG. The drawback of this approach is that the selection feedback gets almost hidden by the background coloring. If the intention is to highlight a search or hightlight a particular values this should not be a serious problem.

The default itemRenderer ADGItemRenderer extends from UITextField (for perforamnce reasons) which doesn't have a backgroundColor style. Hence it is not possible to do it out of the box. But TextField (parent of UITextField) has background and backgroundColor properties which can be set to change the backgroundColor of the TextField.

I have created a new custom itemRenderer ADGItemRendererEx which derives from ADGItemRenderer. I have added a "rowColor" style to this and use this style value to set the TextFields background color.

By providing a styleFunction to ADG we get control to return any styles we want to be set on the itemRenderer. Any logic to determine a particular rows color can go into this function. The return value is a object with style names as properties and style values as proprety-values. For ex:

return { rowColor:0xFF0000, fontWeight:"bold" };

If function logic decides not to change the styles it can return an empty object.

The following sample shows the result. By typing any string in the text box the particular row containing the searched string is highlighted. User can choose to search for either company column or product column.

The source is available here.

63 comments:

DomPazz said...

Works like a charm.

1 Question: What are the pros/cons of resetting the itemRenderer vs. refreshing the dataProvider?

I substituted "adg.dataProvider.refresh()" in your triggerADGUpdate() function.

Pan said...

Great job. The only thing I miss is alpha blending for the background. It appears this is a limitation of UITextField, though.

Sreenivas said...

dataProvider.refresh should serve the purpose. It has the advantage achieveing the result by executing less code ! I don't see any cons.

Marco F said...

NICE work!!!!, but I'm having problems to implement this peace of art, I get an error on the line

Include "DGItemRendererEx.as";
the error reads "Packages can not be nested"

I notice on your example you don't have this line on the .mxml? what am I doing wrong; with out this line I get error on all calls to your custom functions defined on DGItemRendererEx.as";

I will appreciate any help
Marco.

Sreenivas said...

Hi Marco,

going by your words it looks like you are using "include" instead of import !

-Sreenivas

Marco F said...

Thanks Sreenivas! sorry I'm new to Flex, I change from include to import, and I'm getting

ADGItemRendererEx could not be found;

I guess I'll need to know what's the base for this component, hence with the help of intellisece I will reference at easy.

So the question will be what will be the complete line? after the import?

Sreenivas said...

If you place the ADGRowBackground.mxml and ADGItemRenderer.as file in the same source directory then there should not be any need for a import statement. If you have placed the files in different directories then you need to use the standard AS rules of import and package specification for the files.

Suppose you want to move ADGItemRendererEx.as to component directory then modify the package statment in the file to read

package component

and import statment as

import component.ADGItemRendererEx;

Anonymous said...

Hi, i try your example, when i use thtat, the select row style change, and the background color of the rows with content is now white... someone have a solution for that?

Sreenivas said...

You can set the row background color to any specific value by changing the value in the custom itemRenderer used.

Or you can use the approach specified here if you want the row background color to show through. The approach described here doesn't allow this transparency because TextField doesn't have a alpha setting.

Unknown said...

Hi Sreenivas, thanks for the useful tips! Do you know of a way to get this to work with ADGGroupItemRenderer?

Sreenivas said...

The same logic should work with GroupItemRenderers too.

Vivek said...

Sreenivas,

It will be great if you post some example or links for GroupItemRenderer.

Sreenivas said...

If you are looking for any specific groupItemRenderer use-case sample let me know. I can't see what example would be useful.

Anonymous said...

Hy...
very nice..

a question...

i have mydatagrid class taht extends Advanceddatagrid..

mydagrid class has a cunstroctor tha takes an arraycollection of objects...

i put extra emty rows to separate gruops of data...

i would mantain user interaction in data rows and disbale it when there is an empty row? for example disabling the rollover effect..

can you help me?

thanks

Sreenivas said...

I am unable to understand what help you need from me. Are you expecting me to write code for the requirement you have mentioned ? Right now I am neck deep in work so I won't be able to do it.

Unknown said...

The problem with ADGGroupItemRenderer is that it inherits from UIComponent and not UITextField... and in this case, we don't have a backgroundcolor property.

Does anyone have a solution to set the backgroundcolor in the group column too ?

Many thanks in advance

Sreenivas said...

ADGGroupItemRenderer has an embedded UITextField whose background property need to be set.

Unknown said...

Hi Sreenivas,
I have set adg column to editable. When I click on editable cell, the selected cell's background had to be changed. How do i change the selected cell's background?


Thanks,
Srikanth

Sreenivas said...

When DG/ADG is displaying a read only cell value it would be using ADGItemRendrerer or the renderer provided to the column.

When editing starts it starts using the cellEditor itemRenderer which would be a TextInput. So to show a different background color you need to provide your own inherited control as cell editor and set its background color to what ever you wish.

Unknown said...

Hi Sreenivas,
This is a grt example for colouring a complete row.
I am looking for colouring single cell on its click. To be precise, I am trying to replicate the cell selection like in excel.
So when I click on a cell in adg, I need change the background of that cell.
Sample code wud be helpful.Ur help appreciated.

Thanks, Srikanth

Sreenivas said...

ADG already has a cell selection mode. Have you tried using that ?

Sriku said...

Hi Sreenivas

Sriku said...

I got through the cell coloring.
Is there a way to highlight the entire column (column rectangle). Which property has to be modified for this??? Lets say, how to increase the borderThickness of a single column?

Thanks for the quick response Sreenivas .

Sreenivas said...

There is no easy solution to this I guess. The columns are not ui elements and I don't think there is any style for line thickness. You have to derive/override functions to get this behavior.

Unknown said...

In first, thanks for this sample its very helpful.

I want to come back to the problem of the ADGGroupItemRenderer.

In fact, I try your solution which is to do :

super.label.background = true;

But i got this error:

"Cannot access a property or method of a null object reference."

It seems like an initialization problem, but i'm not an expert in the framework.

I'm still looking for a solution but i'm open to any help ;)

shital said...

Hi Sreenivas thanks for the nice post but i have one problem how to set backgroung color for GroupingFields
Plz Help me

krishnanand said...

Hi Sreeni,

I am new to flex.

I am trying to change the background color of the row when the row is selected.

I tried to acieve it by using your approach. But i am not able to doit.

Can you please, let me know, whether this is possible with your approach.

with thanks
Krishnanand.

Sreenivas said...

I am unable to understand whether you want the selection color of data grid to change or keep changing the background color of rows that have been selected.

If you are thinking of doing the later I would advice against it because what I have shown here is an example of changing background color based on data not on user actions.

krishnanand said...

Hi sreeni,

Thanks for your reply.Below is what i want to do.

The user should be allowed to select and unselect multiple rows in a advanceddatagrid (without using Shift or Ctrl key).

When he select a row, the color of the row should be changed to red (so that he can identify that this
row as been selected). When he again select the same row , the color of the row should be changed back to white (Normal color).

I almost achevied this requirement using custom Itemrenderer class.

But i want to make sure whether this is the right way to acheive it.

Any help on this is appreciated.


with thanks,
krishnanand.

Sreenivas said...

krishnanand : IMO you have achieved it the right way by using custom item renderers.

shital : For groupingFields you need to do the same thing in ADGGroupItemRenderer.

ADG uses different itemRenderers for different areas and functionality. Hence you need to work on all the itemRenderers to get the same effect in all of them.

Sreenivas said...

oriop: I think you are trying to set the label background color even before the label is created. You need to find a appropriate place in the code to do it.

Dharmendra said...

Hi Shrinivas,
I am designing highlightng and unhighlghing row functionality for my datagrid and I am almost done with it.I used groupitemrender and item renderer
The only issue which is troubling me is selectionColor.The custom itemerender's sytyle seems to be overriding dataGrid selection color. I need to keep dataGrid slection behavior unchanged. It is just showing border around the slected row.

Please advise me on this.

Thanks,
Dharmendra

videopopcorn said...

Hi srinivas, i am not able to achieve row coloring when i am using the Grouping with ADG and when i use item rendere for a column..can you please provide me a working example, with Grouping (something like tree) and colouring one tree Header node with a different color?Please..
I wanted to complete this ASAP,Please need some help urgent.

Dharmendra said...

Hi Shrini,

I could managed to solve the selectionColor issue.I just conditionaly disabled the backgroud color of label ie

lable.backgroundcolor = false

If anyone need the sample application which supports highlighting in grouped data , pls let me know.

Regards,
Dharmendra


Regards,
Dharmendra

videopopcorn said...

Hello,
Srini can you please share me your email id so that i have some thing which you can help me.please as i could not post mockup image here..(on the blog) my email address is mdevalla@gmail.com you can send me a test mail..Please

DEVSACHIN said...

Hi
I am not able to change the color of UITextField. i had seen the color style is avail in this class. Actually i am creating an item renderer by extending UIComponent and to display text i want to use UITextfiled instead Text.
please help me

Thanks
Sachin dev Tripathi(DevSachin)

Sreenivas said...

Have you set both background and backgroundColor ?

DEVSACHIN said...

No, but now i have used setColor property to change text color of UITextfield. it is mentioned in its document that UITextfield does not support setStyle.
So what to do now when i have to use UITextField as text renderer?

Mic said...

Awesome blog! Regarding your comments about individual cell highlighting a la Excel with selectionMode="singleCell" on adg. This breaks the ability to autoexpand first parent node of tree on construct with selectedIndex = 0; etc as with "singleCell" there is no longer a selection. In order to implement both autoexpand and Excel-like cell highlighting, do you recommend forcing "singleCell" to auto-expand or "singleRow" to do cell selection? TIA, Mic

Mic said...

Awesome blog! Regarding your comments about individual cell highlighting a la Excel with selectionMode="singleCell" on adg. This breaks the ability to autoexpand first parent node of tree on construct with selectedIndex = 0; etc as with "singleCell" there is no longer a selection. In order to implement both autoexpand and Excel-like cell highlighting, do you recommend forcing "singleCell" to auto-expand or "singleRow" to do cell selection? TIA, Mic

Sreenivas said...

@Mic: I am unable to understand your query completely. When selectionMode is singleCell the selection would be available in the selectedCells property. It would be in the form of row and column index. You can use the row index to open the tree node.

Keshav said...

Would it be possible to change the cell background color of an ADG? I've tried many variations but nothing seems to work, and those which worked are quite slow when huge data (2000 rows and 200 columns) is filled in the ADG. Is there an elegant and fast solution for this? BTW, I'm from C# background.

Keshav

phonon56 said...

This was such a treat! Thank you!
phonon56

Mic said...

Thanks for response - got totally sidetracked so have not got back to this one yet .... critical grid problem at present is: how to stop a child row from displaying but still use data in parent summary row (adg with tree column). Reason is that simple SUM on SummaryField is inaccurate in this scenario so child data includes total row that I am 'mining' from parent SummaryField with summaryFunction= "gridUtil.getChildTotFunction" but now need to stop the child total row from displaying. Do not know if this is even possible but you will :-)

Mic said...

Thanks for response - got totally sidetracked so have not got back to this one yet .... critical grid problem at present is: how to stop a child row from displaying but still use data in parent summary row (adg with tree column). Reason is that simple SUM on SummaryField is inaccurate in this scenario so child data includes total row that I am 'mining' from parent SummaryField with summaryFunction= "gridUtil.getChildTotFunction" but now need to stop the child total row from displaying. Do not know if this is even possible but you will :-)

Sreenivas said...

@Mic you can try to use a custom ADGGroupItemRenderer to hide the arrow icon. I am assuming you have only one child row which has the total and you don't want the user to see it.

Mic said...

I have one child "total" row for every parent, but there is no arrow as these children are "2nd column" rows. Is it imposing on you to ask whether I can send a small screenshot to make things clearer? Thanks, Mic.

Sreenivas said...

Yes send me the image.

Keshav said...

Hope, this time, I'll be lucky and get some response. This is a followup to my previous post made on 23rd October.

I've tried to adapt the method outlined in "Showing different icons in each cell of OLAPDataGrid based on the cell value" to achieve individual cell colors on the basis of the data contained in each cell of ADG. Though I was able to render the desired color, CPU usage is maintained at 50% and it take some time to render. And once rendered scrolling the Grid is painfully slow.

My system configuration:

Intel Core2Duo 2.93 Ghz
4 GB RAM
Windows 2003 with SP2
Tested the App in FF 3.5.4 and IE7
Flex SDK 3.2.0

I've another method which does the rendering fast enough, but I'm unable to get the correct values from the Cell. Scrolling the grid using this method is much more responsive, but when loaded with hundreds of rows, its also slow.

I'm at my wits end and need some guidance. I wanted to attach the sample application with this post, couldn't do it hence sending it to your gmail account: sreenivas.ramaswamy@gmail.com

Keshav

Unknown said...

Hi Sreeni,

Thanks for the blog. I have a question on this. Hope you can help me with it. I have flat data and am grouping it in advanceddatagrid. My issue is, I need to change the parent node text color and make it look different from the children. I noticed that some one else asked you the same question. If you have a solution for this adn can share it with me, I would be very much thankful to you.

Thank You.

Regards
Shii

Sreenivas said...

You can use a function like the following as adg.styleFunction

private function myStyleFunction(rowData:Object, column:AdvancedDataGridColumn):Object
{

if (rowData.hasOwnProperty("GroupLabel")) {
return { color:"red" };
}

return {};

}

You can add extra conditions and return different color values.

Sreenivas said...

The hasOwnProperty check is using the fact that the group nodes (parent nodes) have a default property called "GroupLabel".

Unknown said...

Hi Sreenivas,

Thank You so much for the response. I am glad I found your blog.

Regards
Shii

Unknown said...

By You : ADGGroupItemRenderer has an embedded UITextField whose background property need to be set.

Plz tell me how to set background property on ADGGroupItemRenderer which have an embedded UITextField.

It's urgent plz help

Thanks
Mohan

Unknown said...

How can you simply extend the ADG style properties to include setting the rowColor without overriding all of the other defaults or any styles set with mx:Style source="whatEver.css" statements? I'm working on using a CheckBox to set the selectedIndices array and the related rowColor, effectively overriding the default row selection behavior. Thanks!

Sreenivas said...

I am quite getting the exact question here but I will try to answer it from what I have understood.

The rowColor style in the example shown in a style of ADGItemRendererEx and not ADG. So if you specify the rowColor style as a style value for ADGItemRendererEx as detailed here you will be able to set it to any value.

Sreenivas said...

@Mohan : I think the way you set the style doesn't change. Follow the example source given.

Unknown said...

Hi,
I have got one challenging question for which I am banging my head. Let me put the question in a simple way..
I have an Advanced Data grid which has a total of 6 advanceddatagrid columns. Out of the 6 columns 4 of them are divided as AdvancedDatagridGroupedColumns which inturn again have 4 advanced datagrid columns…so the columns are like App_name, A(grouped advanced datagrid colum…inturn contains a1,a2,a3,a4),B(b1,b2,b3,b4),C(c1,c2,c3,c4),D(d1,d2,d3,d4) and Count

I had set the background colors for the 4 grouped column A,B,C and with 4 different colors..

Now my requirement is to get ALTERNATING ROW COLORS for the grouped columns (i.e for A,B,C and D) and not for app_name and Count…

For Eaxample if I give the background color for the grouped Column A as dark Blue then the ALTERNATING ROW COLORS of the grouped column should in such a way that the first row of the a1,a2,a3 and a4 should only be DARK BLUE and the second row of the same grouped column A (a1,a2,a3,a4) should be LIGHT BLUE..

Also another req is that I need to give the header colors to only A,B,C and with their respective background colors.

Here is the samplecode..

######################################### This is my AdvancedData Grid with Grouped Columns ##########################################
































############### This is the StyleFunction Name that I am providing to AdvancedDataGridColumnGroup ################################

private
function ADGStyle(data:Object, col:AdvancedDataGridColumnGroup):Object
{
// var rowColumnIndex:adva
/* var vals:Array = [0, 2, 4, 6];
var i:int = fullDeployDGLinux.dataProvider.getItemIndex(data);
if (vals.indexOf(i) >= 0){
var o:Object = new Object;
//o.color = 0×000000;
//o.fontWeight = “bold”; alternatingItemColors=”[0xFFE0E0, 0xE0E0FF, 0xeaf1dd, 0xe5e0ec]”
o.backgroundColor = 0xFF0000;
return o;
}
else return null; */
if(col.headerText ==”PA1″)
{
Alert.show(
“rakesh”);
var i:int;
var rc:int = fullDeployDGLinux.rowCount;
for(var i=0;i >= rc; i+2)//fullDeployDGLinux.getChildAt(rc %2)
return {rowColor:0xFF0000}; //styleFunction=”ADGStyle”
}
return{rowColor:0×000000}
}

#################################################### I only provided the styleFunction for the first AdvacedDataGridColumnGroup… The ADGStyle function is not being called (tested it using the Alert Statement).. I guess the function needs to get the value from the AdvancedDataGridColumnGroup…I dont know how to pass values to the function as styleFunction is just called by its name and variables cannot be passed by the function..

Also the Header BackGround colors are to be changed only for the Grouped Columns according to their specific Grouped Columns BackGroundColor .. That is also giving me trouble

I had tried out many ways but I m not getting any solution.. I am not sure its correct or not.

I hope you could help me out with this Issue

Unknown said...

Hi Sreenivas ,

Setting the "super.label.background = true" in ADGGroupItemRenderer is not working for me to set the background colour of the grouped nodes. Infact all the data is getting disappeared. Am i missing something ?? This is how my ADGgroupItemRenderer looks like.

import mx.charts.styles.HaloDefaults;
import mx.controls.advancedDataGridClasses.AdvancedDataGridGroupItemRenderer;
import mx.styles.CSSStyleDeclaration;

[Style(name="branchRowColor", type="uint", format="Color", inherit="yes")]
public class ADGGroupRenderer extends AdvancedDataGridGroupItemRenderer
{



public function ADGGroupRenderer()
{
super();
super.label.background = true;
}


private static var stylesInited:Boolean = initStyles();

private static function initStyles():Boolean
{
HaloDefaults.init();

var ADGGroupRendererStyle:CSSStyleDeclaration =
HaloDefaults.createSelector("ADGGroupRenderer");

ADGGroupRendererStyle.defaultFactory = function():void
{
this.branchRowColor = 0xFFFFFF;
}

return true;
}



override public function validateNow():void
{
super.label.backgroundColor = getStyle("branchRowColor");
super.validateNow();
}


The stylefunction that I am using to change the colour at runtime is as follows:

private function myStyleFunction(data:Object, col:AdvancedDataGridColumn):Object
{
var xmlItem:XML=XML(data);
var obj:Object = new Object();
if (xmlItem != null) {
if (xmlItem.@DiffType == "DELETE") {
//obj.color = 0xFF0000;(for text color changes)
obj.rowColor = 0xff0000;
obj.branchRowColor = 0xff0000;

} else if (data.@DiffType == "MODIFY") {
//obj.color = 0xF8c769;
obj.rowColor = 0xF8c769;
obj.branchRowColor = 0xF8c769;

}
}

return obj;
}


Can you point out if I am missing something ?

Thanks in advance,
Smita

Sreenivas said...

I think your code might be running into a NPE because label would not be created in the constructor itself. You need to do the initialization after the label has been created in ADGGroupItemRenderer.createLabel.

trailmarky said...

whoa!!!, you had a passion in blogging, thumbs up for your work of love.. Hehe very inspiring ideas,


anyway I'm william
mind if I put a link back to you?


(clickable) ------> Mens Suits

Unknown said...

Guys I'm getting an error that HaloDefaults.init() Incorrect number of arguments. Expected 1.

Also HaloDefault.createSelector("ADGItemRendererEX") Incorrect number of arguments. Expected 2.

Can any1 please help me with this?

Unknown said...

private static function initStyles():Boolean
{
var style:IStyleManager2 = StyleManager.getStyleManager(null);

HaloDefaults.init(style);

var ADGItemRendererExStyle:CSSStyleDeclaration = HaloDefaults.createSelector("ADGItemRendererEx", style);

ADGItemRendererExStyle.defaultFactory = function():void
{
this.rowColor = 0xFFFFFF;
}

return true;
}