Delphi 7:如何通过点击它们来更改StringGrid上单个单元格的颜色?

时间:2016-10-13 16:23:37

标签: delphi delphi-7

我正在尝试创建一个应用程序,当我点击它们时,removePunctuation的单元格会改变颜色。每次我点击一个单元格时,它应该切换到下一个颜色并保持该颜色,直到我再次点击该单元格,按顺序:

白色==>红色==>橙色==>绿色==>白色(如交通灯)。

我得到的错误有点难以解释,但我会尝试。

应用程序运行,但是当我单击一个单元格然后单击另一个单元格时,有时我单击的第一个单元格会改变颜色,但第二个单元格不会。其他时候,两个细胞都会改变颜色。其他时候,两个细胞都会重置为白色状态。

TStringGrid

1 个答案:

答案 0 :(得分:3)

问题是您正在使用OnDrawCell事件来更新状态机。切勿使用绘图事件来推动状态变化!由于许多原因,UI控件经常被绘制,因此任何绘图事件都应该仅绘制当前正在绘制的特定项目的当前状态。您应该使用OnSelectCellOnClick事件来更新状态机,然后触发重新绘制已更新的单元格。

试试这个:

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;