Link to home
Start Free TrialLog in
Avatar of LeTay
LeTay

asked on

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 ?
Avatar of akb
akb
Flag of Australia image

OnSelectCell is the event you need to use
Avatar of LeTay
LeTay

ASKER

Well, OnSelectCell refers to the new selected one
I need to manipulate the data from the Cell that had the focus just before ...
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.
ASKER CERTIFIED SOLUTION
Avatar of jimyX
jimyX

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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'.
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
yeah, but InplaceEdit is still active in that case ... so closing InplaceEdit comes after he loose a focus.