2010. november 15., hétfő

Highlight an entire row in a TStringGrid (2)


Problem/Question/Abstract:

I have a TStringGrid component and I want change the color of the text in one row.

Answer:

Any kind of custom drawing in a TStringgrid requires a OnDrawCell handler (or overriding the DrawCell method in a derived grid class). Often this is not enough,however. If you base your special drawing on the active cell or its row or column you also need to make sure cells you previously drew in your custom manner are redrawn normal when the active cell moves, that the grid shows the special drawing only when it has focus and so on. This can get a bit complex, as shown by the sample below.

Note that is is simpler when you only customize the active cell, since this cell will be redrawn automatically when it is activated or deactivated.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, StdCtrls, Grids;

const
  UM_INVALIDATEROW = WM_USER + 321;
type
  TForm1 = class(TForm)
    StatusBar: TStatusBar;
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    Label1: TLabel;
    StringGrid1: TStringGrid;
    Edit1: TEdit;
    procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect;
      State: TGridDrawState);
    procedure StringGrid1Enter(Sender: TObject);
    procedure StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer; var
      CanSelect: Boolean);
    procedure StringGrid1Exit(Sender: TObject);
  private
    { Private declarations }
    FGridActive: Boolean;
    procedure UMInvalidateRow(var msg: TMessage); message UM_INVALIDATEROW;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  dummy: Integer;

implementation

{$R *.DFM}

type
  TGridCracker = class(TStringgrid); { gives access to protected methods }

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  grid: TStringgrid;
begin
  {Task: color the current row}
  grid := Sender as TStringgrid;
  if FGridActive and (aRow = grid.Row) and (aCol >= grid.FixedCols) then
  begin
    grid.Canvas.brush.Color := clBlue;
    grid.canvas.font.color := clWhite;
    grid.canvas.FillRect(Rect);
    InflateRect(rect, -2, -2);
    grid.Canvas.TextRect(Rect, rect.left, rect.top, grid.cells[aCol, aRow]);
  end
  else if (gdSelected in State) and not grid.Focused then
  begin
    grid.Canvas.brush.Color := grid.color;
    grid.canvas.font.color := grid.font.color;
    grid.canvas.FillRect(Rect);
    InflateRect(rect, -2, -2);
    grid.Canvas.TextRect(Rect, rect.left, rect.top, grid.cells[aCol, aRow]);
  end;
end;

procedure TForm1.StringGrid1Enter(Sender: TObject);
begin
  if Sender is TStringgrid then
    with TGridCracker(sender) do
      PostMessage(self.handle, UM_INVALIDATEROW, Row, Integer(sender));
  FGridActive := true;
  { Cannot rely on grid.focused here, it is not yet true when the message send
  above is processed for some reason. }
end;

procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
  var CanSelect: Boolean);
var
  grid: TStringgrid;
begin
  grid := Sender as TStringgrid;
  if grid.Row <> aRow then
    PostMessage(handle, UM_INVALIDATEROW, grid.Row, Integer(grid));
  PostMessage(handle, UM_INVALIDATEROW, aRow, Integer(grid));
end;

procedure TForm1.UMInvalidateRow(var msg: TMessage);
begin
  TGridCracker(msg.lparam).InvalidateRow(msg.wparam);
end;

procedure TForm1.StringGrid1Exit(Sender: TObject);
begin
  if Sender is TStringgrid then
    with TGridCracker(sender) do
      PostMessage(self.handle, UM_INVALIDATEROW, Row, Integer(sender));
  FGridActive := false;
end;

end.

Nincsenek megjegyzések:

Megjegyzés küldése