-1

I've written some code which colours individual cells on my stringgrid, within my delphi application, according to a list of data.

I now need to write some code in the OnDblClick event on my stringgrid which deduces whether or not a cell is coloured and then proceeds according to the result found. For instance:

DOUBLE CLICK CELL  
IS CELL COLOURED  
  YES > PROCEED A  
  NO > PROCEED B
Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
Babah254
  • 13
  • 4
  • 9
  • 3
    You should ask the underlying data (that list of data you've mentioned) by the currently selected cell coordinates for this condition. – TLama Mar 21 '13 at 18:30
  • do you "color" your cells in a paint event or do you have a underlying coloring structure? – jachguate Mar 21 '13 at 18:34
  • @TLama I could use the data within my list to find out if the cell is occupied, but that seems like a long way around the problem. @jachguate I colour the cells using a `Rect` property. I have just tried to use `if StringGrid.Canvas.Pixels[ACol, ARow] <> $00FFFFFF then` and it seems to work, but only some of the time. I'm not sure what's causing it to behave unpredictably. – Babah254 Mar 21 '13 at 18:48
  • No, that's the proper way! You're trying to workaround it. Moreover, in a wrong way. The `Canvas.Pixels` takes pixel coordinates, not grid cell coordinates. You'd have to get cell rectangle of the currently selected cell and determine the color from inside this rectangle if so, but it's just evil. – TLama Mar 21 '13 at 18:54
  • @TLama I see what you're saying, however, I may have forgot to mention that not all my data in the list corresponds to a cell. The data may correspond to a cell and the it and a varying number of the cells below it will be coloured. Therefore, my list of data does not show all of the cells which are coloured. This is why I am looking for a solution which uses the cell colour. – Babah254 Mar 21 '13 at 18:59
  • You might use [`this`](http://pastebin.com/NpMTrT30) to get color of the currently selected cell's pixel on coordinates `[1;1]`. – TLama Mar 21 '13 at 19:16
  • @TLama It works a treat if I change the values to +2. Maybe because I have fixedcells. Thanks. – Babah254 Mar 21 '13 at 19:20
  • 1
    TLama's original comment contains the insight. It's best to separate the application logic from the presentation. – David Heffernan Mar 21 '13 at 19:25

1 Answers1

1

Store the color at the time you draw it into the predefined TStringGrid.Objects property. When you need to retrieve it, you can get it back from the Column and Row coordinates. Here's a trivial example that stores either clWhite or clBlack in the Objects for the cell based on whether or not it's an odd-numbered column, and simply displays the stored value as a string when the cell is selected. It should get you started.

procedure TForm1.FormCreate(Sender: TObject);
var
  r, c: Integer;
const
  ColorSel: array[Boolean] of TColor = (clWhite, clBlack);
begin
  StringGrid1.RowCount := 10;
  StringGrid1.ColCount := 6;
  for c := 1 to StringGrid1.ColCount - 1 do
    for r := 1 to StringGrid1.RowCount - 1 do
    begin
      StringGrid1.Cells[c, r] := Format('C: %d R: %d', [c, r]);
      StringGrid1.Objects[c, r] := TObject(ColorSel[Odd(c)]);
    end;
end;

procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
  var CanSelect: Boolean);
begin
  ShowMessage(ColorToString(TColor(StringGrid1.Objects[ACol, ARow])));
end;

You can use this in the OnMouseUp event easily to detect what color is in the cell. Remove the StringGrid1SelectCell (using the Object Inspector, just remove the value for the event) and add this as the OnMouseUp event for the grid instead:

procedure TForm1.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  Col, Row: Integer;
begin
  StringGrid1.MouseToCell(X, Y, Col, Row);
  if (Col > -1) and (Row > -1) then
    ShowMessage(ColorToString(TColor(StringGrid1.Objects[Col, Row])));
end;

Handling the double-click then becomes pretty easy (thanks to @TLama for a big assist):

procedure TForm1.StringGrid1DblClick(Sender: TObject);
var
  IsDefaultColor: Boolean;
  CurrCellColor: TColor;
  CurrCol, CurrRow: Integer;
begin
  // Save typing by grabbing the currently selected cell col/row
  CurrCol := StringGrid1.Col;   
  CurrRow := StringGrid1.Row;

  // Get the stored color for the selected cell
  CurrCellColor := TColor(StringGrid1.Objects[CurrCol, CurrRow]);

  // See if it's been painted a different color than the default
  IsDefaultColor := (CurrCellColor = StringGrid1.Color);

  if not IsDefaultColor then
    HandleDifferentColorCell
  else
    HandleNormalColorCell;
end;

Note that if you're choosing not to change the color for a cell, you should still assign the default color of the cell to the Objects[Column, Row] so that there's something meaningful there in order to avoid an improper conversion when retrieving the value.

Ken White
  • 123,280
  • 14
  • 225
  • 444
  • @TLama: I know that. :-) I figured I'd leave something for the OP to work out. ;-) I could have mentioned `Mouse.CursorPos` in passing, I guess, since `OnDblClick` doesn't include coordinates. Thanks, too. :-) – Ken White Mar 21 '13 at 23:15
  • @TLama: (In my best Homer Simpson voice) "Doh!" You're right. There's a much simpler solution using your thought. I just over-thought it. Re-editing and deleting my last couple of comments before this one. Thanks. :-) – Ken White Mar 21 '13 at 23:44
  • @TLama: Fixed the OnDblClick handler, with proper credit given to you. :-) Thanks again. – Ken White Mar 21 '13 at 23:51
  • "Mouse.CursorPos in passing, I guess, since OnDblClick doesn't include coordinates. " And that sometimes lead to quite unpleasant bugs, when `Mouse.CursorPos` returns coordinate far away from coordinates at the moment of the click... – Arioch 'The Mar 22 '13 at 07:39
  • @Arioch, in the `OnDblClick` event you can get the grid coordinates simply with `Row` and `Col` properties as the first click of a double click selects the cell (if you don't prevent it somehow, of course). About mouse cursor position, the `Mouse.CursorPos` calls internally `GetCursorPos` Windows API function, so you'll get the *fresh* current cursor position. – TLama Mar 22 '13 at 10:04
  • yeah, the "fresh" is exactly the issue with VCL mouse events... :-) I know, i just wanted to warn those, who did not thought about it... – Arioch 'The Mar 22 '13 at 11:49