How can I make all my grids look the same way all over my forms? I want to implement an alternate row color that must be applied on all grids of my project. Is it possible without adding the same DrawColumnCell event code for every grid? I want to avoid adding the same code for each of my grids. I have like 30 grids in my project and multiplied by 13 rows of code it just adds a lot of code lines to my project making it "unfriendly". I am looking for a solution that will only add 13 lines of code to the project, not 390 lines.
My formatting code looks like this (for example):
procedure TDBGrid.DBGrid1DrawColumnCell(Sender: TObject;const Rect: TRect;DataCol: Integer;Column: TColumn;State: TGridDrawState) ;
var
grid : TDBGrid;
row : integer;
begin
grid := sender as TDBGrid;
row := grid.DataSource.DataSet.RecNo;
if Odd(row) then
grid.Canvas.Brush.Color := clSilver
else
grid.Canvas.Brush.Color := clDkGray;
grid.DefaultDrawColumnCell(Rect, DataCol, Column, State) ;
end;
Probably I would need to extend the DBGrid somehow, but I do not know exactly how nor how to look for a solution for this on google
I tried to hack the DBGRid inside each form like this:
type
TDBGrid = class(DBGrids.TDBGrid)
protected
procedure DrawColumnCell(const Rect: TRect; DataCol: Integer;Column: TColumn; State: TGridDrawState); override;
end;
...
procedure TDBGrid.DrawColumnCell(const Rect: TRect; DataCol: Integer;Column: TColumn; State: TGridDrawState) ;
var
grid : TDBGrid;
row : integer;
begin
row := 2;//grid.DataSource.DataSet.RecNo;
if Odd(row) then
Canvas.Brush.Color := clSilver
else
Canvas.Brush.Color := clDkGray;
DefaultDrawColumnCell(Rect, DataCol, Column, State) ;
end;
I can do this but I cannot access the sender, so I can access the dataset and know which record to color and which not (odd and even). And this is a poor approach anyways since I will have to do it on every form, so it's not really a solution
Any ideas?
Thank you
If you put something like this in your datamodule, and assign it to the OnDrawColumnCell
of every DBGrid, it seems to work (see notes that follow):
procedure TDataModule1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
const
RowColors: array[Boolean] of TColor = (clSilver, clDkGray);
var
OddRow: Boolean;
begin
// Safety check, although it really isn't needed; no other control accepts
// this event handler definition, AFAIK, so the only way to call it with the
// wrong Sender type would be to do so in your own code manually. In my own
// code, I'd simply leave out the check and let the exception happen; if I
// was stupid enough to do so, I'd want my hand slapped rudely.
if (Sender is TDBGrid) then
begin
OddRow := Odd(TDBGrid(Sender).DataSource.DataSet.RecNo);
TDBGrid(Sender).Canvas.Brush.Color := RowColors[OddRow];
TDBGrid(Sender).DefaultDrawColumnCell(Rect, DataCol, Column, State);
end;
end;
A couple of notes:
First, you should avoid using TDataSet.RecNo
in the first place, because post-BDE datasets don't typically have this value available. Accessing it (particularly on large or query-based datasets) causes a major performance hit to your application. Of course, not using it means that you can't use this solution. A better solution would be to use a handler for the dataset's BeforeScroll or AfterScroll event that toggled a boolean available to this code instead, and use that instead of the test for Odd(RecNo)
, or if the dataset is only used for displaying in the DBGrid, use the TDataSet.Tag
in the AfterScroll
event to track the row's odd/even state using
OddRow := Boolean(DataSet.Tag);
DataSet.Tag := Ord(not OddRow);
Add DBGrids to the uses clause of your datamodule, and manually declare the above event in the published
section so that it's available to all units that use the datamodule. You can then assign it in the Object Inspector Events tab as usual from those units.
This does not properly handle the TGridDrawState
(nor does your initial code). You'll need to add handling for that yourself, as that wasn't what you asked here.
Depending on which color you want for odd and even rows, you may want to reverse the order of the colors in RowColors
.
I prefer the repeated typecasts so that it's clear what the code is doing. If it bothers you, you can simply declare a local variable instead:
var
OddRow: Boolean;
Grid: TDBGrid;
begin
if (Sender is TDBGrid) then
begin
Grid := TDBGrid(Sender);
OddRow := Odd(Grid.DataSource.DataSet.RecNo);
...
end;
end;