Event leaving a cell in a TStringGrid

I have a TStringGrid component that has editable cells (options ...)
I want to catch the event that the focus is "leaving" the current selected cell, for example when the user clicks on another cell
Which event is it ?
LVL 1
LeTayAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

akbCommented:
OnSelectCell is the event you need to use
LeTayAuthor Commented:
Well, OnSelectCell refers to the new selected one
I need to manipulate the data from the Cell that had the focus just before ...
akbCommented:
You are correct. The OnSelectCell fires when you move from one cell to another but returns the new cell info. You could put in code to keep track of the cell you are leaving.
Another option is to use TStringAlignGrid from SourceForge. Have a look here:
http://sourceforge.net/projects/stringaligngrid/
Click on the Code tab.
OWASP: Avoiding Hacker Tricks

Learn to build secure applications from the mindset of the hacker and avoid being exploited.

jimyXCommented:
Hi LeTay,
One way to achieve that with the default StringGrid, as already suggested by akb, which I would do, instead of changing to a third-party, i.e using the OnSelectCell event to store pointer to the current selected cell and keep track of Cell changes by comparing to the previously selected cell:  
...
TForm1 = class(TForm)
...
    StringGrid1: TStringGrid;
    procedure FormCreate(Sender: TObject);
    procedure StringGrid1SelectCell(Sender: TObject; aCol, aRow: Integer;
      var CanSelect: Boolean);
  private
    { private declarations }
    CurrCell: TPoint;
  public
    { public declarations }
  end; 

var
  Form1: TForm1;

implementation

...

procedure TForm1.StringGrid1SelectCell(Sender: TObject; aCol, aRow: Integer;
  var CanSelect: Boolean);
begin
  if not PointsEqual(CurrCell,  Point(ACol, ARow)) then
    begin
      //Cell has changed, what you want to do, goes here
      caption:= 'New cell: '+ IntToStr(ACol)+':'+IntToStr(ARow)+' - Old Cell: '+ IntToStr(CurrCell.x)+':'+IntToStr(CurrCell.y);

      //update the pointer for detecting the next change
      CurrCell:= Point(ACol, ARow);
    end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  CurrCell:= Point(StringGrid1.Col, StringGrid1.Row); // just initiation
end;

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Sinisa VukSoftware architectCommented:
Another way is to override InplaceEdit's window procedure.
Here is my code (although answer is accepted, but  4 the record...):
...
const
  WM_INPLACEEDIT_EXIT = WM_USER + $100;

type
  TStringGridHelper = Class(TStringGrid);

...
TForm1 = class(TForm)
...
    procedure FormCreate(Sender: TObject);
    procedure StringGrid1GetEditText(Sender: TObject; ACol, ARow: Integer;
      var Value: String);
    procedure StringGrid1Exit(Sender: TObject);
...
    OldWndProc, NewWndProc: TFarProc;
    hCurrentInplaceEdit: HWND;
    procedure HookInplaceEdit(hw: HWND);
    procedure InplaceEditWndProc(var Message: TMessage);
    procedure UnHookInplaceEdit(hw: HWND);
    procedure InplaceEditOnExit(var Message: TMessage); message WM_INPLACEEDIT_EXIT;
...

procedure TForm1.FormCreate(Sender: TObject);
begin
  hCurrentInplaceEdit := 0;
  OldWndProc := nil;
  NewWndProc := nil;
end;

procedure TForm1.StringGrid1GetEditText(Sender: TObject; ACol,
  ARow: Integer; var Value: String);
begin
  if Assigned(TStringGridHelper(StringGrid1).InplaceEditor) then
    HookInplaceEdit(TStringGridHelper(StringGrid1).InplaceEditor.Handle);
end;

procedure TForm1.StringGrid1Exit(Sender: TObject);
begin
  if Assigned(TStringGridHelper(StringGrid1).InplaceEditor) then
    UnHookInplaceEdit(TStringGridHelper(StringGrid1).InplaceEditor.Handle);
end;

procedure TForm1.HookInplaceEdit(hw: HWND);
begin
  if hCurrentInplaceEdit = 0 then
  begin
    OldWndProc := TFarProc(GetWindowLong(hw, GWL_WNDPROC));
    NewWndProc := Classes.MakeObjectInstance(InplaceEditWndProc);
    SetWindowLong(hw, GWL_WNDPROC, LongInt(NewWndProc));
    hCurrentInplaceEdit := hw;
    //SendMessage(Self.Handle, WM_INPLACEEDIT_EXIT, 1, 0);
  end;
end;

procedure TForm1.UnHookInplaceEdit(hw: HWND);
begin
  if hCurrentInplaceEdit > 0 then
  begin
    SetWindowLong(hw, GWL_WNDPROC, LongInt(OldWndProc));
    hCurrentInplaceEdit := 0;
    if Assigned(NewWndProc) then
    begin
      Classes.FreeObjectInstance(NewWndProc);
      NewWndProc := nil;
    end;
    //SendMessage(Self.Handle, WM_INPLACEEDIT_EXIT, 2, 0);
  end;
end;

procedure TForm1.InplaceEditWndProc(var Message: TMessage);
begin
  //call old proc
  Message.Result := CallWindowProc(OldWndProc, hCurrentInplaceEdit, Message.Msg,
    Message.wParam, Message.lParam);

  if Message.Msg = WM_KILLFOCUS then
  begin
    PostMessage(Self.Handle, WM_INPLACEEDIT_EXIT, 0, MakeLong(StringGrid1.Col, StringGrid1.Row));
  end;
end;

procedure TForm1.InplaceEditOnExit(var Message: TMessage);
begin
  if Message.WParam = 0 then
  begin
    StringGrid1.Cells[Message.LParamLo, Message.LParamHi] := '111';
  end;
end;

Open in new window


... where InplaceEditOnExit is event procedure fired on Exit from Inplace Editor (Stringgrid). My example (quite complicated) force to change text to '111'.
Geert GOracle dbaCommented:
To add ... and make things way more complex

you don't get a focus change when clicking on a speedbutton
so be carefull with those types of buttons
Sinisa VukSoftware architectCommented:
yeah, but InplaceEdit is still active in that case ... so closing InplaceEdit comes after he loose a focus.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.