How to fill cell of a string grid using custom color?

Rabi Jayasawal picture Rabi Jayasawal · Oct 14, 2015 · Viewed 9.3k times · Source

I am trying to write custom date picker(calendar). The dates will be displayed on the stringgrid. I am trying to fill the clicked cell with a custom color and make that selected celltext bold.

Here is my code:

    type
      TStringGrid = Class(Vcl.Grids.TStringGrid)
      private
        FHideFocusRect: Boolean;
      protected
         Procedure Paint;override;
      public
         Property HideFocusRect:Boolean Read FHideFocusRect Write FHideFocusRect;
      End;


    TfrmNepaliCalendar = class(TForm)
    ...
    ...
    ...
    end;


    procedure TfrmNepaliCalendar.StringGridDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    begin
       if gdSelected in State then begin
        StringGrid.Canvas.Brush.Color := $00940A4B;
        StringGrid.Canvas.FillRect(Rect);

        StringGrid.Canvas.Font.Style := [fsBold];
        StringGrid.Canvas.Font.Color := clHighlightText;
        StringGrid.Canvas.TextOut(Rect.Left + 3, Rect.Top + 5, StringGrid.Cells[ACol,ARow]);

        StringGrid.HideFocusRect := True;
      end;
    end;


{ TStringGrid }

procedure TStringGrid.Paint;
var
  LRect: TRect;
begin
  inherited;
  if HideFocusRect then begin
    LRect := CellRect(Col,Row);
    if DrawingStyle = gdsThemed then InflateRect(LRect,-1,-1);

    DrawFocusrect(Canvas.Handle,LRect)
  end;
end;

The output, I am getting:

When clicked on cell containing no text

When clicked, the background is clipped from left

Problem #1: I need to hide that unwanted rectangle appearing as border for the selected cell

Problem #2: Avoid the cell background clipping

Answer

Tom Brunberg picture Tom Brunberg · Oct 14, 2015

In the OnDrawCell procedure add just before FillRect

Rect.Left := Rect.Left-4;

Seems to work.


An alternative

The above doesn't fully solve the focus issue even with your paint procedure addon. Sometimes a white line is visible just inside the cell borders.

But the following is an alternative, that solves both your issues. It requires a little more coding, but not so much. On the other hand, subclassing TStringGrid is not needed, neither the Rect adjustment

The basis is to disable default drawing, so set the grids property DefaultDrawing := false; and then add to the OnDrawCell event:

procedure TForm1.StringGridDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  if gdFixed in State then
  begin
    StringGrid.Canvas.Brush.Color := clGradientInactiveCaption;
    StringGrid.Canvas.Font.Style := [];
    StringGrid.Canvas.Font.Color := clBlack;
  end
  else
  if gdSelected in State then
  begin
    StringGrid.Canvas.Brush.Color := $00940A4B;
    StringGrid.Canvas.Font.Style := [fsBold];
    StringGrid.Canvas.Font.Color := clHighlightText;
  end
  else
  begin
    StringGrid.Canvas.Brush.Color := $00FFFFFF;
    StringGrid.Canvas.Font.Style := [];
    StringGrid.Canvas.Font.Color := clWindowText;
  end;

  StringGrid.Canvas.FillRect(Rect);
  StringGrid.Canvas.TextOut(Rect.Left + 3, Rect.Top + 5, StringGrid.Cells[ACol,ARow]);
end;

With default drawing disabled, the grid draws the grid frame and the grid lines, but leaves all other drawing to the programmer. The caveat is that you have to add fancy themed drawing yourself if you need it. With above coding I get this result:

Sample grid