Ben Crain
The gridlines aren't very flexible, but you can turn them off and draw
anything you want into the cell, by using the OnDrawCell event. First, set
the GrideLineWidth property to zero, then provide this sort of
OnDrawCellEvent handler:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Grids;
type
TForm1 = class(TForm)
StringGrid1: TStringGrid;
procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
public
function InMatrix(ACol, ARow: Integer): Boolean;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
function TForm1.InMatrix(ACol, ARow: Integer): Boolean;
begin
Result := (ACol > 1) and (ACol < 4) and (ARow > 1) and (ARow < 4);
end;
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
begin
if InMatrix(ACol, ARow) then
begin
with StringGrid1.Canvas do
begin
Pen.Color := clBlue;
Pen.Width := 1;
Rectangle(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom);
end;
end;
end;
end.
Cheers Derham McAven
No, that was clear, but I was expecting you to extrapolate from the example
:).
> So I don't want to draw rectangles around single cells, but around
> submatrices containing several cells
So implement this logic in your OnDrawCell event handler. You'll need a way
to determine for any particular cell which combination of edges (top, left,
bottom, right) need to be drawn. You can obtain this information from your
submatrix data structure, and then use MoveTo and LineTo to draw lines only
on the necessary edges.
>The code above obliterates what's in the cells
See below.
> A further curiosity: the DrawCell event also produces a continual
> "flickering" of the StringGrid
The flickering and obliteration are caused by the combination of
DefaultDrawing set to True, and using Canvas.Rectangle.
With DefaultDrawing = True, the Delphi grid component draws the cell, and
then fires your OnDrawCell event. The string grid will draw the text into
the cell. The Rectangle method draws a rectangle, but also fills in the
interior of the rectangle in the brush color. This overwrites the text drawn
by the grid -- hence flicker and obliteration.
Either a) don't overwrite the contents of the cell drawn by the grid, or b)
set DefaultDrawing to False and do all of your own drawing, including
drawing the text with Canvas.TextRect.
This example doesn't overwrite the grid cell contents, so you won't see
flicker nor will you need to use TextRect:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Grids, Buttons;
type
TForm1 = class(TForm)
StringGrid1: TStringGrid;
procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
type
TCellEdge = (ceLeft, ceTop, ceRight, ceBottom);
TCellEdges = set of TCellEdge;
function GetEdges(ACol, ARow: Integer): TCellEdges;
begin
Result := [];
{ Hard-coded simulated matrix data }
{ Replace with intelligent algorithm based on your submatrix structure }
if (ACol = 1) and (ARow = 1) then Result := [ceLeft, ceTop]
else if (ACol = 1) and (ARow = 3) then Result := [ceLeft, ceBottom]
else if (ACol = 3) and (ARow = 1) then Result := [ceRight, ceTop]
else if (ACol = 3) and (ARow = 3) then Result := [ceRight, ceBottom]
else if (ACol = 1) and (ARow = 2) then Result := [ceLeft]
else if (ACol = 3) and (ARow = 2) then Result := [ceRight]
else if (ARow = 1) and (ACol = 2) then Result := [ceTop]
else if (ARow = 3) and (ACol = 2) then Result := [ceBottom];
end;
procedure DrawEdges(Canvas: TCanvas; ARect: TRect; Edges: TCellEdges;
AColor: TColor; AWidth: Integer);
begin
with Canvas do
begin
Pen.Color := AColor;
Pen.Width := AWidth;
if ceLeft in Edges then
begin
MoveTo(ARect.Left, ARect.Top);
LineTo(ARect.Left, ARect.Bottom + 1);
end;
if ceRight in Edges then
begin
MoveTo(ARect.Right - 1, ARect.Top);
LineTo(ARect.Right - 1, ARect.Bottom);
end;
if ceTop in Edges then
begin
MoveTo(ARect.Left, ARect.Top);
LineTo(ARect.Right , ARect.Top);
end;
if ceBottom in Edges then
begin
MoveTo(ARect.Left, ARect.Bottom - 1);
LineTo(ARect.Right , ARect.Bottom - 1);
end;
end;
end;
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
var
Edges: TCellEdges;
begin
Edges := GetEdges(ACol, ARow);
DrawEdges(StringGrid1.Canvas, Rect, Edges, clBlack, 1);
end;
end.
- Rick