문제

라자 러스 V0.9.30 (32 비트 컴파일러)을 실행하고 있습니다.

표준 TStringGrid가있는 TForm이 있습니다. 그리드에는 다음과 같은 속성이 설정되어 있습니다. rowcount= 5, columncount= 5, fixedcols= 0, fixedrows= 0.

코드 셀 색상을 변경하는 방법을 보여주었습니다. 사용자가 TStringGrid 셀을 클릭하면 셀에 텍스트를 추가하십시오. 모든 것이 잘 작동하고 그리드 클럭 이벤트에서 색상 / 텍스트를 켜고 끄기 위해 약간 확장되었습니다.

내가 가진 질문은 코드의 일부 요소의 일부 뒤에서 더 잘 이해할 수있는 것이 더 많습니다.

foregroud (fg) 및 배경 (bg) TColor 객체의 배열이 있습니다. GridClick 이벤트에 설정된 셀 색상 속성을 저장할 수 있으므로 DrawCell 이벤트가 셀이 다시 다시 그릴 수있는 이유로 다시 트리거 될 필요가있는 경우? TCCLORS 배열을 사용하지 않고 필요에 따라 DrawCell 이벤트의 색상 / 텍스트를 설정할 수 있습니까?

배열을 사용해야하는 경우, 차원은 grid.count 및 grid.rowcount (즉, setLength 호출을 통해 설정된 setLength 호출을 통해 설정하십시오)

이라고 가정합니다.

StringGrid의 5 x 5 셀 외부에서 클릭하고 있으며 따라서 GridClick이 DrawCell 이벤트를 호출하는 것을 방지하는 방법이 있습니다. 어디에서나 든 항상 행과 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.
.

도움이 되었습니까?

해결책

AllowOutboundEvents to False를 설정하십시오. OnClick 이벤트는 클릭 할 때만 해고됩니다. 공백을 클릭하면 특정 셀이 아닙니다. 따라서이 속성을 사용하면 어딘가를 클릭하면 항상 유효한 셀 좌표를 얻을 수 있습니다.

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

다른 점은 OnPrepareCanvas OnDrawCell에서 텍스트 렌더링을 포함하여 모든 것을 페인트해야하기 때문에 OnDrawCell 대신 이벤트. OnPrepareCanvas Brush.Color 렌더링 될 각 셀에 대해

, 배열을 사용할 필요가 없으므로 Font.Color 란 열에 있었지만 분명히 배열에 색상을 유지할 수 있습니다. 다음 예제에서는 Objects 이벤트 이벤트의 사용을 보여줍니다. 이 예제는 질문에서뿐만 아니라 고정 된 것들을 포함한 모든 셀을 색상화합니다 :

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;
.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top