我正在尝试创建一个应用程序,当我点击它们时,removePunctuation
的单元格会改变颜色。每次我点击一个单元格时,它应该切换到下一个颜色并保持该颜色,直到我再次点击该单元格,按顺序:
白色==>红色==>橙色==>绿色==>白色(如交通灯)。
我得到的错误有点难以解释,但我会尝试。
应用程序运行,但是当我单击一个单元格然后单击另一个单元格时,有时我单击的第一个单元格会改变颜色,但第二个单元格不会。其他时候,两个细胞都会改变颜色。其他时候,两个细胞都会重置为白色状态。
TStringGrid
答案 0 :(得分:3)
问题是您正在使用OnDrawCell
事件来更新状态机。切勿使用绘图事件来推动状态变化!由于许多原因,UI控件经常被绘制,因此任何绘图事件都应该仅绘制当前正在绘制的特定项目的当前状态。您应该使用OnSelectCell
或OnClick
事件来更新状态机,然后触发重新绘制已更新的单元格。
试试这个:
type
TForm1 = class(TForm)
StringGrid: TStringGrid;
procedure StringGridDrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
procedure StringGridSelectCell(Sender: TObject; ACol, ARow: Integer;
var CanSelect: Boolean);
private
arrState: array[1..4, 1..4] of Integer;
end;
procedure TForm1.StringGridDrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
const
clOrange = TColor($008CFF);
CellColors: array[0..3] of TColor = (clWhite, clRed, clOrange, clGreen);
begin
if (ACol in [1..4]) and (ARow in [1..4]) then
begin
StringGrid.Canvas.Brush.Color := CellColors[arrState[ARow, ACol]];
StringGrid.Canvas.FillRect(Rect);
end;
end;
// TStringGrid.InvalidateCell() is protected,
// but can be reached using an accessor class..
type
TStringGridAccess = class(TStringGrid)
end;
procedure TForm1.StringGridSelectCell(Sender: TObject; ACol, ARow: Integer;
var CanSelect: Boolean);
begin
if (ACol in [1..4]) and (ARow in [1..4]) then
begin
arrState[ARow, ACol] := (arrState[ARow, ACol] + 1) mod 4;
TStringGridAccess(StringGrid).InvalidateCell(ACol, ARow);
end;
end;
可替换地:
type
TForm1 = class(TForm)
StringGrid: TStringGrid;
procedure StringGridClick(Sender: TObject);
procedure StringGridDrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
private
arrState: array[1..4, 1..4] of Integer;
end;
// TStringGrid.InvalidateCell() is protected,
// but can be reached using an accessor class..
type
TStringGridAccess = class(TStringGrid)
end;
procedure TForm1.StringGridClick(Sender: TObject);
type
POINTS = packed record
x: SHORT;
y: SHORT;
end;
var
dwPos: DWORD;
pts: POINTS absolute dwPos;
pt: TPoint;
iCol, iRow: Integer;
begin
dwPos := GetMessagePos();
pt := StringGrid.ScreenToClient(Point(pts.x, pts.y));
StringGrid.MouseToCell(pt.X, pt.Y, iCol, iRow);
if (iCol in [1..4]) and (iRow in [1..4]) then
begin
arrState[iRow, iCol] := (arrState[iRow, iCol] + 1) mod 4;
TStringGridAccess(StringGrid).InvalidateCell(iCol, iRow);
end;
end;
procedure TForm1.StringGridDrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
const
clOrange = TColor($008CFF);
CellColors: array[0..3] of TColor = (clWhite, clRed, clOrange, clGreen);
begin
if (ACol in [1..4]) and (ARow in [1..4]) then
begin
StringGrid.Canvas.Brush.Color := CellColors[arrState[ARow, ACol]];
StringGrid.Canvas.FillRect(Rect);
end;
end;