1

I have a stringgrid that shows a bunch of files and information about those files. More info is shown about the current selected item in a separate panel. So, I want to know when the selected row changes to update the panel. OnSelectCell is not good because it triggers BEFORE the selection is actually moved to the new location. This is what I mean:

function TStrGrd.SelectCell(ACol, ARow: Longint): Boolean;   {override}
begin
 Result:= inherited SelectCell(ACol, ARow);
 Mesage('Cur row: '+ IntToStr(row));
 Mesage('New row: '+ IntToStr(ARow));

 { My own event }
 if Assigned(FCursorChanged)
 then FCursorChanged(Self);            <-------- user will see the old row
end;

If the last row is selected and I click the first row, I will get these messages:

Cur row: 999
New row: 0

It would work if I create my own event handler and pass to it the row where the selection IS GOING TO be moved. It should work 100% but I am not very happy with this because the user would have to write some extra code in that event handler.

I could intercept all user interactions (mouse/key down) and all selection changes I do programatically but this requires quite a lot of code. There should be a more elegant way.

  1. This question is similar to What event fires every time a TDbGrid's selected location is changed? but not a duplicate. The answer to that question was 'use OnDataChange' but the TStringGrid doesn't have that event.
  2. @Andriy M suggests here why OnSelectCell won't work: Detecting single vs multiple selections in Delphi TStringGrid
Community
  • 1
  • 1
Gabriel
  • 20,797
  • 27
  • 159
  • 293
  • What do you mean "before the selection is actually moved"? The `Row` and `Col` have changed. – David Heffernan Jan 23 '14 at 19:43
  • 2
    I expect you can PostMessage (POST not SEND) to your grid, some kind of your own WM_USER+delta. I expect that to the moment when all other messages would be handled and you would get that your own custom message - all the work including changing properties and painting would already be done. Actually PostMessage is the most typical for WinGDI/VCL way to offload some task. // However my guts feeling suggest that you just trying to you wrong tool. Describe the problem as whole, what is happening that you try to solve by delayed event handler? maybe you can solve it in more VCL-like ways ? – Arioch 'The Jan 23 '14 at 20:38

1 Answers1

1

Not an answer. Just posting it to have multiline text.

I think you meant "to UPDATE the panel" rather than "to about" :-)

Still I cannot get what is wrong with a ROW parameter. You say "user would have to write some extra code in that event handler." but actually it is the opposite.

procedure ParamEvent(const grid: TStringGrid; const Row: integer); 
begin
  ..do something with    grid.Rows[Row] to update the panel

//  ...and if I need, I also already know which Row was selected beforehand!
end;

procedure ParamLessEvent(); 
var grid: TStringGrid; Row: integer;    // <<<<< EXTRA "coding" here
begin
  grid :=  ..... some way to get the needed grid      // <<<<< EXTRA coding here
  Row  :=  grid.Row;        // <<<<< EXTRA coding here

  ...do something with    grid.Rows[Row] to update the panel

//  ...and if I would want to know which file just was DE-selected,
//   I would have to code persisting of previous selected row 
//   number somewhere outside the grid
end;

now, really, why not use PostMessage ?

const WM_Grid_Event = WM_USER + 123; // I hope it is correct? I always mix wm_user and wm_app
type TMyGrid = class (TStringGrid)
   ....
     private
       procedure DelayedEvent(var MSG: TMessage); message WM_Grid_Event;
     end;

function TMyGrid.SelectCell(ACol, ARow: Longint): Boolean;   {override}
begin
 Result:= inherited SelectCell(ACol, ARow);
 Mesage('Cur row: '+ IntToStr(row));
 Mesage('New row: '+ IntToStr(ARow));

 PostMessage( Self.Handle, WM_Grid_Event, ARow, 0);
end;

procedure DelayedEvent(var MSG: TMessage);
begin
  { My own event }
  if not Assigned(FCursorChanged) then exit;

  if Self.Row = MSG.WParam (* changed already? *) then begin
     FCursorChanged(Self);
  end else begin
     if MSG.LParam < 5 then // protection from infinite loop. OTOH I hope we would not EVER got here
        PostMessage( Self.Handle, WM_Grid_Event, MSG.WParam, 1 + MSG.LParam);
  end;
end;
Arioch 'The
  • 15,799
  • 35
  • 62