2016-10-13 11 views
0

Я пытаюсь создать приложение, в котором ячейки TStringGrid меняют цвет, когда я нажимаю на них. Каждый раз, когда я нажимаю на ячейку, он должен переключиться на следующий цвет и оставаться в этом цвете до тех пор, пока я не нажму на эту ячейку снова, в порядке:Delphi 7: Как я могу изменить цвета отдельных ячеек на StringGrid, нажав на них?

белый ==> красный ==> оранжевый ==> зеленый = => белый (например, светофор).

Ошибка (ы) Я получаю немного сложно объяснить, но я попробую.

Приложение запускается, но когда я нажимаю на одну ячейку, а затем на другую, иногда первая ячейка, на которую я нажимал, меняет цвет, а второй - нет. В других случаях обе ячейки меняют цвет. В других случаях обе ячейки просто восстанавливаются до их белого состояния.

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; 

ответ

3

Проблема в том, что вы используете событие OnDrawCell, чтобы обновить свой конечный автомат. НИКОГДА не используйте событие рисования для изменения состояния накопителя! Элемент управления пользовательским интерфейсом обрабатывается часто и по многим причинам, поэтому любые события рисования должны рисовать только текущее состояние для конкретного элемента, который в настоящее время рисуется. Вы должны использовать событие OnSelectCell или OnClick для обновления вашего конечного автомата, а затем вызвать перерисовку обновленной ячейки.

Попробуйте это:

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; 
+0

Спасибо вам большое! – Ragglepop