我正在运行Lazarus v0.9.30(32位编译器)。
我有一个带有标准TStringGrid的TForm。网格具有以下属性集。 RowCount = 5,ColumnCount = 5,FixedCols = 0,FixedRows = 0.
我用Google搜索了一些code,它向我展示了当用户点击TStringGrid单元格时如何更改单元格颜色并向单元格添加一些文本。一切正常,我已经稍微扩展它以在GridClick事件上打开和关闭颜色/文本。
我的问题更多是为了更好地理解代码中某些元素背后的目的。
有一系列Foregroud(FG)和背景(BG)TColor对象。它们是否存储在GridClick事件上设置的单元格颜色属性,因此如果由于任何原因需要再次触发DrawCell事件,则单元格可以自行重绘?您可以避免使用TColors数组,只需根据需要在DrawCell事件中设置颜色/文本吗?
如果你需要使用数组,我会假设维度必须与Grid.ColCount和Grid.RowCount匹配(即通过Form.Create中的SetLength调用设置)
有没有办法检测到你在stringgrid的5 x 5单元格外(即在空白区域内)点击,从而阻止GridClick调用DrawCell事件。无论你在哪里点击,你总能获得Row和Col的有效值。
unit testunit;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
ExtCtrls, Menus, ComCtrls, Buttons, Grids, StdCtrls, Windows, Variants,
LCLType;
type
{ TForm1 }
TForm1 = class(TForm)
Grid: TStringGrid;
procedure FormCreate(Sender: TObject);
procedure GridClick(Sender: TObject);
procedure GridDrawCell(Sender: TObject; aCol, aRow: Integer;
aRect: TRect; aState: TGridDrawState);
end;
var
Form1: TForm1;
implementation
var
FG: array of array of TColor;
BG: array of array of TColor;
{$R *.lfm}
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
var
Col, Row: integer;
begin
// Set the sizes of the arrays
SetLength(FG, 5, 5);
SetLength(BG, 5, 5);
// Initialize with default colors
for Col := 0 to Grid.ColCount - 1 do begin
for Row := 0 to Grid.RowCount - 1 do begin
FG[Col, Row] := clBlack;
BG[Col, Row] := clWhite;
end;
end;
end;
procedure TForm1.GridDrawCell(Sender: TObject; aCol, aRow: Integer;
aRect: TRect; aState: TGridDrawState);
var
S: string;
begin
S := Grid.Cells[ACol, ARow];
// Fill rectangle with colour
Grid.Canvas.Brush.Color := BG[ACol, ARow];
Grid.Canvas.FillRect(aRect);
// Next, draw the text in the rectangle
Grid.Canvas.Font.Color := FG[ACol, ARow];
Grid.Canvas.TextOut(aRect.Left + 22, aRect.Top + 2, S);
end;
procedure TForm1.GridClick(Sender: TObject);
var
Col, Row: integer;
begin
Col := Grid.Col;
Row := Grid.Row;
// Set the cell color and text to be displayed
if (Grid.Cells[Col,Row] <> 'Yes') then
begin
BG[Col, Row] := rgb(131, 245, 44);
FG[Col, Row] := RGB(0, 0, 0);
Grid.Cells[Col, Row] := 'Yes'
end {if}
else
begin
BG[Col, Row] := rgb(255, 255, 255);
FG[Col, Row] := RGB(255, 255, 255);
Grid.Cells[Col, Row] := '';
end; {else}
end;
end.
答案 0 :(得分:4)
如果您将AllowOutboundEvents
设置为False
,则OnClick
事件仅在您单击某个单元格时触发,而不是在您单击空格时触发。因此,如果您使用此属性,则在单击某处时将始终获得有效的单元格坐标。
procedure TForm1.FormCreate(Sender: TObject);
begin
StringGrid1.AllowOutboundEvents := False;
...
end;
另一点是,您应该使用OnPrepareCanvas
事件而不是OnDrawCell
,因为在OnDrawCell
中您必须绘制所有内容,包括文本呈现。使用OnPrepareCanvas
,您只需为要呈现的每个单元格设置Brush.Color
和Font.Color
。
而且,您不需要使用数组,您可以像使用列一样使用Objects
,但肯定可以保留数组中的颜色。在下面的示例中,我使用了Objects
,并且还显示了OnPrepareCanvas
事件的用法,但请注意,此示例以及您的问题将使所有单元格(包括固定单元格)着色:< / p>
type
TCellData = class(TObject)
private
FStateYes: Boolean;
FForeground: TColor;
FBackground: TColor;
public
property StateYes: Boolean read FStateYes write FStateYes;
property Foreground: TColor read FForeground write FForeground;
property Background: TColor read FBackground write FBackground;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Col, Row: Integer;
CellData: TCellData;
begin
for Col := 0 to StringGrid1.ColCount - 1 do
for Row := 0 to StringGrid1.RowCount - 1 do
begin
CellData := TCellData.Create;
CellData.StateYes := False;
CellData.Foreground := clBlack;
CellData.Background := clWhite;
StringGrid1.Objects[Col, Row] := CellData;
end;
StringGrid1.AllowOutboundEvents := False;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
Col, Row: Integer;
begin
for Col := 0 to StringGrid1.ColCount - 1 do
for Row := 0 to StringGrid1.RowCount - 1 do
StringGrid1.Objects[Col, Row].Free;
end;
procedure TForm1.StringGrid1Click(Sender: TObject);
var
Col, Row: Integer;
CellData: TCellData;
begin
Col := StringGrid1.Col;
Row := StringGrid1.Row;
if StringGrid1.Objects[Col, Row] is TCellData then
begin
CellData := TCellData(StringGrid1.Objects[Col, Row]);
if CellData.StateYes then
begin
StringGrid1.Cells[Col, Row] := '';
CellData.StateYes := False;
CellData.Foreground := RGB(255, 255, 255);
CellData.Background := RGB(255, 255, 255);
end
else
begin
StringGrid1.Cells[Col, Row] := 'Yes';
CellData.StateYes := True;
CellData.Foreground := RGB(0, 0, 0);
CellData.Background := RGB(131, 245, 44);
end;
end;
end;
procedure TForm1.StringGrid1PrepareCanvas(sender: TObject; aCol, aRow: Integer;
aState: TGridDrawState);
var
CellData: TCellData;
begin
if StringGrid1.Objects[ACol, ARow] is TCellData then
begin
CellData := TCellData(StringGrid1.Objects[ACol, ARow]);
StringGrid1.Canvas.Brush.Color := CellData.Background;
StringGrid1.Canvas.Font.Color := CellData.Foreground;
end;
end;