Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations derfloh on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

TStringGrid and cell colors

Status
Not open for further replies.

tamara3776

Programmer
Apr 6, 2004
18
US
I am having alot of difficulty trying to accomplish this. I have a data entry form with a string grid on it. When the user hits the submit button the form will be validated and the fields with errors will be colored red. I need to know how to color the individual cells in the grid that have errors. I have yet to figure this out and any help would be great.

Thanks
 
please check out FAQ section : faq102-2416

--------------------------------------
What You See Is What You Get
 
Would this still apply even though I am using StringGrid and not a DBGrid?
 
In your string grid, there's an event 'OnDrawCell', create a procedure for drawing the cell. Here's some code I use to check for the number of people assigned, however I am ONLY checking one column in the grid (which is why it is always (3, ARow), you are going to want (ACol, ARow)). If there is more than 90 the entire row is RED, if it is more than 85 and less than 90 the row is yellow and if it is more than 80 and less than 85 it is blue. Will need some slight modification to color an individual cell, but this should get you in the right direction.

Leslie


Code:
procedure TfrmMain.sgStatusCounterDrawCell(Sender: TObject; ACol,
  ARow: Integer; Rect: TRect; State: TGridDrawState);
begin
  With Sender as TStringGrid do
  begin
    if cells[3, ARow] <> '' then
    begin
      if IsNumeric(cells[3, ARow]) then
      begin
        if StrToInt(cells[3, ARow]) >= 90 then
        begin
          //for BackGround  Color
          Canvas.Brush.Color := clRed;
          Canvas.FillRect(Rect);
          //for Font.Color
          Canvas.Font.Color := clBlack;
          Canvas.TextRect( Rect, Rect.Left+2, Rect.Top+2, Cells[acol, arow]);
        end
        else if (StrToInt(cells[3, ARow]) >= 85) and (StrToInt(cells[3, ARow]) <= 89) then
        begin
          //for BackGround  Color
          Canvas.Brush.Color := clYellow;
          Canvas.FillRect(Rect);
          //for Font.Color
          Canvas.Font.Color := clBlack;
          Canvas.TextRect( Rect, Rect.Left+2, Rect.Top+2, Cells[acol, arow]);
        end
        else if (StrToInt(cells[3, ARow]) > 80) and (StrToInt(cells[3, ARow]) < 85) then
        begin
          //for BackGround  Color
          Canvas.Brush.Color := clSkyBlue;
          Canvas.FillRect(Rect);
          //for Font.Color
          Canvas.Font.Color := clBlack;
          Canvas.TextRect( Rect, Rect.Left+2, Rect.Top+2, Cells[acol, arow]);
        end;
      end;
    end;
  end;
end;
 
Thanks,
I will give it a go to see if I can modify it to work with my application. Much appreciated
 
after looking at this a little closer, here's where it colors the whole row:
Code:
Canvas.TextRect( Rect, Rect.Left+2, Rect.Top+2, Cells[acol, arow]);

by modifying it to this:
Code:
Canvas.TextRect( Rect, Rect.Left, Rect.Top, Cells[acol, arow]);

it should only color the individual cell.

HTH

Leslie
 
Is there any way around the fact that the cell has to be selected for it to be colored.
 
The cell doesn't have to be selected in my app using this code.

Leslie
 
Hmmm interesting.
Is the default drawing property of your String Grid set to false or true?
 
I put your code into my app and tested it and it did color the cell that errored out immediately. However when I clicked on other cells they were getting colored as well. I initially used this code that you provided:

Code:
Canvas.TextRect( Rect, Rect.Left+2, Rect.Top+2, Cells[acol, arow]);

and then changed it to this code

Code:
Canvas.TextRect( Rect, Rect.Left, Rect.Top, Cells[acol, arow]);

but still had the same result. Do you happen to have any other suggestions?
 
I guess I was wrong about that, it still colored the whole row for me too!

here's where it colors the cell:

//for BackGround Color
Canvas.Brush.Color := clRed;
Canvas.FillRect(Rect);

What's the code you are using?

les

 
It seems like I have tried a million things and it still does not want to work the way that I need it to. If you can take a look at my code to see if you can find anything wrong I would greatly appreciate it.

Code:
with (Sender as TStringGrid) do
  begin
    if (ErrList.Count > 0) then
    begin
      for i := 0 to ErrList.Count - 1 do
      begin
        errCol := StringReplace(LeftStr(ErrList[i], 2), ',', '', [rfReplaceAll, rfIgnoreCase]);
        errRow := StringReplace(RightStr(ErrList[i], 2), ' ', '', [rfReplaceAll, rfIgnoreCase]);

        canvas.Brush.Color := ErrColor;
        Canvas.FillRect(Rect);
      end; //for ErrList
    end; //If ErrList
  end; //With TStringGrid

My code even seems like there is something missing now. I have changed it so many times. Anyways let me explain what I need to happen or what I am trying to do with this.

I have a StringList called ErrList which gets populated with the cells that have errors. Could look like:
(1,2);(1,3);(1,4); etc.

if that StringList has a count greater then 0 then I need to color the cells. So then I would loop through each item in the String List to pull out the cell locations (errCol, errRow) that need to be colored. And then I would color them.

What I am wondering now is how does it know what cells to color because I obviously do not have that in there anymore.

I think I am starting to drive myself crazy with this code so any input you have would be greatly welcomed. Thanks for everything you've done already and I hope you will have another answer for me.
 
ok, this code will only work when it is drawing the cell, looking at the information in the cell in the grid.

For instance, my grid looks like this:

Code:
_________________________________
            |     |     |        |
Date        | WS  | PP  | TOTAL  |
____________|_____|_____|________|
            |     |     |        |
12/20/2004  | 32  | 55  |   87   |  <-
____________|_____|_____|________|
            |     |     |        |
12/27/2004  | 16  | 30  |   46   |
____________|_____|_____|________|
            |     |     |        |
1/3/2005    | 8   | 27  |   35   |
____________|_____|_____|________|

So, when the data is being drawn to the cell, it checks the value of the third column, if it is within the parameters it changes the colors. In this example the row indicated with <- has a yellow background with black font.

Now, could you draw a picture like this of what your grid looks like and what criteria you want to use to color the row?

Leslie
 
tamara3776,

The way I would tackle this problem is as follows.

A TStringGrid object contains a property called Cells which you store the text you want displayed. You are already familar with this.

TStringGrid also contains a similar array property called Objects.

You can use the Objects property for whatever you like. One use would be to specify the colour you want the cell to be painted.

So you could have some code assigning the clRed colour to the Objects property of various cells.

Note that the Objects property is of type TObject and colours are of type TColor. So it will be necessary to change the types when assigning one to the other.

Let's say you have a TStringGrid, called grid, which displays numbers and you want any negative numbers displayed with a clRed background.

You will need to have a procedure which assigns either clWhite or clRed to the appropriate Objects property. You might arrange to call this whenever you change a value in the grid.
Code:
begin
for c := 0 to grid.ColCount - 1 do
  for r := 0 to grid.RowCount - 1 do
    if Negative(c,r) then
      grid.Objects[c,r] := TObject(clRed)
    else
      grid.Objects[c,r] := TObject(clWhite);
end;
The Negative function is one that you would code yourself to return TRUE if that particular cell contains a negative value or false otherwise. At its simplest it could look something like:
Code:
function TForm1.Negative(c, r: integer): boolean;
begin
  result := LeftStr(grid.cells[c,r],1) = '-';
end;

You now need to code an OnDrawCell event handler. At its simplest it would look something like this:
Code:
procedure TForm1.gridDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  grid.Canvas.Brush.Color := TColor(grid.Objects[ACol,Arow]);
  grid.Canvas.TextRect(Rect,Rect.Left,Rect.Top,grid.Cells[ACol,ARow] );
end;
In reality your OnDrawCell event handler will be more complex than this. For example, you might have fixed columns and rows. You might wish to left justify the numbers and so on.

Andrew
Hampshire, UK
 
I did something simular to towerbase but created a type with a colour field.

Code:
  Cellcolour := TCellCol.Create;
  Cellcolour.Colour := ClWhite;
  for A := 0 to 1999 do
     begin
        idata.cells[0,A] := inttostr(A);
        idata.Objects[0,A] := Cellcolour;
     end;

//and in the drawcell routine
// notice this line make a copy of the ondrawcell's row 
//parameter this isnt directly relevent but it can cause 
//some odd problems if you dont know about it  
R := row;  // Copy variable 'row' as it only  seems to   be valid for a short time
  

  canvas.brush.color := (objects[0, R] as TCellcol).colour;
  canvas.fillrect(rect);
  canvas.textout(rect.left + 2, rect.top + 2,list.strings[count]);

Its the same thing as towers code really, but it could be extended to hold other information in the TCellcol object

Steve
Be excellent to each other and Party on!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top