简体   繁体   中英

Delphi DBGrid alternate row colors for all DBGrids in the project

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; 

This works for Delphi XE7

type
  TDBGrid=Class(Vcl.DBGrids.TDBGrid)
    procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
  end;

procedure TDBGrid.WMVScroll(var Message: TWMVScroll);
begin
  Self.Invalidate;
  inherited;
end;

procedure TForm1. DBGrid1MouseWheel(Sender: TObject; Shift: TShiftState;
  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
begin
  if Sender is TDBGrid then
    (Sender as TDBGrid).Invalidate;
end;

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
const
  MyRowColors : array[Boolean] of TColor = (clLime, clMoneyGreen);
var
  RowNo  : Integer;
  OddRow : Boolean;
  S      : string;
begin
  if Sender is TDBGrid then begin
    with (Sender as TDBGrid) do  begin
      if (gdSelected in State) then begin
        // Farbe für die Zelle mit dem Focus
        // color of the focused row
        Canvas.Brush.Color := clblue;
      end   
      else  begin
        // count := trunc((Sender as TDBGrid).Height div (Rect.Bottom - Rect.Top));
        // RowNo := (Sender as TDBGrid).Height div Rect.Top;
        RowNo := Rect.Top div (Rect.Bottom - Rect.Top);
        OddRow := Odd(RowNo);
        Canvas.Brush.Color := MyRowColors[OddRow];

        // Font-Farbe immer schwarz
        // font color always black
        Canvas.Font.Color := clBlack;
        Canvas.FillRect(Rect);
        // Denn Text in der Zelle ausgeben
        // manualy output the text
        if Column.Field <> nil then begin
          S := Column.Field.AsString;
          Canvas.TextOut(Rect.Left + 2, Rect.Top + 1, S);
          //  Canvas.TextOut(Rect.Left + 2, Rect.Top + 1, 'Column.Field.AsString');
        end;
      end;
    end 
  end; 
end;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM