1

I am running Lazarus 0.9.30.2.

I have a TForm on which there is a TStringGrid. Each column title is a TGridColumns object that I added dynamically to the grid at run time. Each column title has an object associated with it (that I created and have stored in a TList). I want to paint the background of the column title cells of the string grid, but I don't want all of the cells to be the same colour. Depending on the value of one of the properties in the object associated with the column title, the colour will vary.

I know that there are answers regarding how to paint TStringGrid cells in Stackoverflow (example), that talk about using the string grids DrawCell event to paint the cells, but I'm not sure how to invoke this procedure.

Is the correct approach to have another procedure that identifies the cell of interest (ie identifies the cells 'Rect' property), sets the colour that I want, that then invokes a common DrawCell procedure of the grid to do the actual colouring?

Community
  • 1
  • 1
user1174918
  • 525
  • 6
  • 22

1 Answers1

2

There's a better event for this purpose, the OnPrepareCanvas. This event is being fired whenever the cell is preparing to draw itself and in that stage you can modify some of the canvas attributes, like brush color for painting the background. So what you need is to store the color somewhere:

type
  TTmColumnTitle = class(TTmObject)
  private
    FCellColor: TColor;
  public
    property CellColor: TColor read FCellColor write FCellColor;
  end;

And write the handler for the OnPrepareCanvas event:

procedure TForm1.StringGrid1PrepareCanvas(sender: TObject; aCol, aRow: Integer;
  aState: TGridDrawState);
var
  ColumnTitle: TTmColumnTitle;
begin
  if ARow = 0 then
  begin
    ColumnTitle := TTmColumnTitle(StringGrid1.Objects[ACol, ARow]);
    if Assigned(ColumnTitle) then
      StringGrid1.Canvas.Brush.Color := ColumnTitle.CellColor;
  end;
end;  

Object Inspector with OnPrepareCanvas event shown:

TLama
  • 75,147
  • 17
  • 214
  • 392
  • Thanks for the answer. I have a set of grids and for all of them I load the Grid Columns and assign the TTmColumnTitle objects to the cells as part of the TForm1.Create constructor. The OnPrepareCanvas event is called prior to the TForm1.Create so 'ColumnTitle := TTmColumnTitle(StringGrid1.Objects[ACol, ARow])' returns a Nil object). Is there a way to move the loading of the Grid Columns prior to the OnPreparecanvas event, or can I somehow trigger this event after the TForm1.Create? – user1174918 Mar 06 '12 at 11:09
  • 1
    The form's `OnCreate` event is being fired once and prior to string grid's `OnPrepareCanvas`. The `OnPrepareCanvas` is fired for each cell when it is being painted and it is done not once but whenever the cell need the visual refresh. To your question how to invoke the event to be fired, you might use e.g. `StringGrid1.DrawRow(0);`, but what you are describing is strange. The events are fired automatically by component. You only write code which is being performed in their handlers. – TLama Mar 06 '12 at 11:35
  • 1
    I think you misunderstood the component event handling, check e.g. [`this tutorial`](http://delphi.about.com/od/beginners/l/aa052802b.htm). Also you don't need to override form's constructor, you should write the event handler (see the screenshot in my answer). You can simply select the form with mouse, go to the `Object Inspector`, `Events` tab, and click the `...` button at `OnCreate` and write the code there. – TLama Mar 06 '12 at 11:36
  • 1
    Yes....my constructor was wrong. I fixed it up like you indicated and it all works fine now. – user1174918 Mar 06 '12 at 14:22