【问题标题】:Delphi 7: How can I change the colors of individual cells on a StringGrid via clicking on them?Delphi 7:如何通过单击更改 StringGrid 上单个单元格的颜色?
【发布时间】:2016-10-13 16:23:36
【问题描述】:

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

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

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

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

type
  TForm1 = class(TForm)
    StringGrid: TStringGrid;
    procedure StringGridDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
  private
    arrState: array[1..4, 1..4] of Integer;
end;

procedure TForm1.StringGridDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  iRow, iCol: Integer;
  arrk: array[1..4, 1..4] of Integer;
begin
  for iCol := 4 downto 1 do
  begin
    for iRow := 4 downto 1 do
    begin
      if (gdSelected in State) then
      begin
        case arrState[ARow, aCol] of
           0: begin
             StringGrid.Canvas.Brush.Color := clWhite;
             Rect := StringGrid.CellRect(iCol, iRow);
             StringGrid.Canvas.FillRect(Rect);
             Inc(arrState[iRow, iCol]);
           end;

           1: begin
             StringGrid.Canvas.Brush.Color := clRed;
             Rect := StringGrid.CellRect(iCol, iRow);
             StringGrid.Canvas.FillRect(Rect);
             Inc(arrState[iRow, iCol]);
           end;

           2: begin
             StringGrid.Canvas.Brush.Color := $008CFF;
             Rect := StringGrid.CellRect(iCol, iRow);
             StringGrid.Canvas.FillRect(Rect);
             Inc(arrState[iRow, iCol]);
           end;

           3: begin
             StringGrid.Canvas.Brush.Color := clGreen;
             Rect := StringGrid.CellRect(iCol, iRow);
             StringGrid.Canvas.FillRect(Rect);
             arrState[iRow, iCol] := 0;
           end;

         end;
       end;
     end;
   end;
 end;

【问题讨论】:

    标签: delphi delphi-7


    【解决方案1】:

    问题是您正在使用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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-12
      • 2016-08-12
      • 1970-01-01
      相关资源
      最近更新 更多