views:

670

answers:

4

I've got a TDbGrid in my project, and I'm trying to have an event go off every time I change the selected row. Any change in row already updates all the data-aware controls linked to the same DataSource, but there are other changes to be made too, that I need an event handler for.

I thought OnColEnter would work. According to the helpfile, it fires when:

  • The user navigates to the cell using the keyboard. For example, when the user uses the Tab key, or the Home key.

  • The user clicks the mouse button down in the cell.

  • The SelectedField or SelectedIndex property is set.

Unfortunately, it does not fire when the user navigates using the keyboard while the dgRowSelect option is enabled, and there's no OnRowEnter. And the OnKeyDown event fires before the selection change has been made. I'm trying to simulate a data-aware version of a TListBox here, and I need something to replace the List Box's OnClick handler, which despite the name actually goes off anytime the selection is changed, whether through the mouse or the keyboard. Is there any way I can do that with a TDbGrid? If not, there's got to be some other grid control that will do it. Does anyone know what it is? (Preferably open source?)

+7  A: 

Have you tried OnDataChange event of DataSource?

That's the right answer.
Nick Hodges
Well, if Nick said so, I guess I'll have to accept it. I had to do some extra work to keep the stupid thing from firing every time any change was made to the dataset, such as while I'm still populating it, during which time the code in the handler causes AVs. I wish there was a better solution.
Mason Wheeler
+1  A: 

Use the OnDataChange and to handle the case where your loading the dataset, add a boolean check as the first line of the routine, and set this to false when your loading is complete.

procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
  if fbLoading then exit;
  // rest of your code here
end;

procedure TForm1.Form1Create(Sender:tObject);
begin
  fbLoading := true;
  // load your table here     
  fbLoading := false; 
end;
skamradt
+3  A: 

OnDataChange is one choice. The other is, on TDataset side, the event AfterScroll. Most times, I found it more practical than OnDataChange; because in OnDataChange a scroll event comes with the Field parameter nil (which is a trap and can be one of the cause of your AVs coding it).

Fabricio Araujo
Yeah, I think I like that one better.
Mason Wheeler
A: 

I would only use AfterScroll on the dataset, it is fired when you first open the dataset, and every time you move in it. In a DBGrid, that would be on every click on a row, or the scrollbar, or using the keyboard (Home, Edn, Up, Down, PgUp,PgDown) ...etc.

You could even dynamically assign it if you use the same Dataset in many different forms (Either in Create/Free or Show/Close):

procedure TForm1.myAfterScroll(DataSet: TDataSet); 
begin
   //do your thing here
   if oldAfterScroll<>nil then
      oldAfterScroll(DataSet);
end;

constructor TForm1.Create(AOwner: TComponent);
begin
   oldAfterScroll:=DBGrid1.DataSet.OnAfterScroll;
   DBGrid1.DataSet.OnAfterScroll:=myAdrerScroll;
end;

destructor TForm1.Free;
begin
   DBGrid1.DataSet.OnAfterScroll:=oldAfterScroll;
end;
Osama ALASSIRY