2012-03-13 4 views
3

Lazarus v0.9.30 (32 비트 컴파일러)을 실행하고 있습니다.TStringGrid의 셀 색상과 텍스트를 켜고 끄는 방법

표준 TStringGrid가있는 TForm이 있습니다. 그리드에는 다음과 같은 속성 집합이 있습니다.

나는 사용자가 TStringGrid 셀을 클릭 할 때 셀 색상을 변경하고 셀에 텍스트를 추가하는 방법을 보여준 일부을 검색했습니다. 모두 잘 작동하고 GridClick 이벤트에서 색상/텍스트를 켜고 끄기 위해 약간 확장했습니다.

내가 가진 질문은 코드의 일부 요소 뒤에있는 목적을 더 잘 이해하는 것입니다.

FG (Foregroud) 및 Background (BG) TColor 개체 배열이 있습니다. GridClick 이벤트에 설정된 셀 색상 속성을 저장합니까? 그렇다면 어떤 이유로 든 DrawCell 이벤트를 다시 트리거해야하는 경우 셀이 다시 그릴 수 있습니까? TColors 배열 사용을 피하고 필요에 따라 DrawCell 이벤트의 색상/텍스트를 설정하면됩니까? 당신은 배열을 사용해야하는 경우, 내가 치수는 Grid.ColCount 일치 Grid.RowCount해야한다고 가정 할

(예. Form.Create에서 SetLength를 호출을 통해 설정)

감지하는 방법이 있나요 stringgrid (예 : 공백)의 5 x 5 셀 바깥 쪽을 클릭하여 GridClick이 DrawCell 이벤트를 호출하지 못하도록합니다. 당신은 당신이 특정 셀을 클릭 할 때 FalseAllowOutboundEvents에서, OnClick 이벤트는 해고 될 것입니다 설정하면 당신을 클릭 상관없이 항상 행과 골

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. 

답변

4

에 대한 올바른 가치를 얻을, 당신은 클릭하지 않을 때 공백에. 따라서이 속성을 사용하면 어딘가를 클릭 할 때 유효한 셀 좌표를 항상 얻을 수 있습니다.

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

또 다른 점은 OnDrawCell에 텍스트 렌더링을 포함한 모든 페인트해야하기 때문에 당신이 대신 OnDrawCellOnPrepareCanvas 이벤트를 사용한다는 것입니다. OnPrepareCanvas을 사용하면 렌더링 할 각 셀에 대해 Brush.ColorFont.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; 
+1

무엇을 확실하지 : 다음 예제에서 나는이 예제뿐만 아니라 질문에서 당신 같은이 고정 포함한 모든 셀 색상 화하는 Objects을 사용했습니다 또한 OnPrepareCanvas 이벤트의 사용을 나타내고,하지만주의 당신은 TCustomStringGrid 객체를 사용하는 것을 의미합니까? TColors를 저장하는 코드의 작성자에는 다차원 배열이 있습니다. TCustomStringGrid를 사용하면 어떻게 도움이됩니까? – user1174918

+0

오해의 소지가 있습니다. 일부 힌트와 예제를 수정하고 추가했습니다. – TLama

+0

Ok .... 나는 당신이하고있는 것을보고 ..... 모든 셀에 객체를로드 할 계획이었습니다 ... 'StateYes'와 같은 속성을 가지고 있기 때문에 TColor 속성을 추가해야합니다. . 질문 :이 답변에서와 같이 셀 그리기에 그리드 DrawCell 이벤트를 사용하지 않았습니까? [링크] (http://stackoverflow.com/questions/6701462/delphi-how-can-i-change-color-of-a-cell-in-string-grid) – user1174918

관련 문제