【问题标题】:How To Toggle The cell Colour And Text In A TStringGrid On And Off如何打开和关闭 TStringGrid 中的单元格颜色和文本
【发布时间】:2012-03-13 12:52:07
【问题描述】:

我正在运行 Lazarus v0.9.30(32 位编译器)。

我有一个带有标准 TStringGrid 的 TForm。网格具有以下属性集。 RowCount = 5,ColumnCount = 5,FixedCols = 0,FixedRows = 0。

我在 Google 上搜索了一些 code,它向我展示了如何在用户单击 TStringGrid 单元格时更改单元格颜色并向单元格添加一些文本。一切正常,我稍微扩展了它以在 GridClick 事件上打开和关闭颜色/文本。

我的问题更多是为了更好地理解代码中某些元素背后的目的。

有一组 Foregroud (FG) 和 Background (BG) TColor 对象。它们是否用于存储在 GridClick 事件上设置的单元格颜色属性,所以如果 DrawCell 事件因任何原因需要再次触发,则单元格可以重绘自身?能否避免使用 TColors 数组,而只根据需要在 DrawCell 事件中设置颜色/文本?

如果您需要使用数组,我会假设维度必须与 Grid.ColCount 和 Grid.RowCount 匹配(即通过 Form.Create 中的 SetLength 调用设置)

有没有办法检测到您正在单击字符串网格的 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.

【问题讨论】:

    标签: lazarus tstringgrid text-rendering


    【解决方案1】:

    如果您将AllowOutboundEvents 设置为False,则OnClick 事件将仅在您单击某个单元格时触发,而不是在您单击空格时触发。所以如果你使用这个属性,当你点击某个地方时,你总是会得到有效的单元格坐标。

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      StringGrid1.AllowOutboundEvents := False;
      ...
    end; 
    

    另一点是您应该使用OnPrepareCanvas 事件而不是OnDrawCell,因为在OnDrawCell 中您必须绘制所有内容,包括文本渲染。使用OnPrepareCanvas,您只需为要渲染的每个单元格设置Brush.Color 和Font.Color。

    而且,您不需要使用数组,您可以像处理列一样使用Objects,但您当然可以将颜色保留在数组中。在下面的示例中,我使用了 Objects 并且还显示了 OnPrepareCanvas 事件的用法,但请注意,此示例以及问题中的示例会为所有单元格着色,包括固定单元格:

    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;
    

    【讨论】:

    • 不确定使用 TCustomStringGrid 对象是什么意思?代码的作者有多维数组来存储 TColors.....使用 TCustomStringGrid 对我有什么帮助?
    • 抱歉误导了您。修复并添加了一些其他提示和示例。
    • 好的....我知道你在做什么.....我打算用一个对象加载每个单元格....我只需要添加 TColor 属性,因为我有一个类似于“StateYes”的属性。一个问题:您没有使用 grids DrawCell 事件来绘制这个答案中的单元格吗? link
    • 是的,因为 Delphi 没有 OnPrepareCanvas,他们只有 OnDrawCell,正如您在那篇文章中看到的,还必须渲染文本本身。如果您只想修改要呈现的单元格的画布属性,例如背景或字体颜色,那么OnPrepareCanvas 是正确的阶段。关于StateYes,您当然可以使用Yes 字符串比较,但如果您想更改它,例如将来Yeah,您将不得不在多个地方更改它:-)
    猜你喜欢
    • 2016-02-21
    • 2011-12-24
    • 2014-01-05
    • 2022-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    • 1970-01-01
    相关资源
    最近更新 更多