views:

77

answers:

2

I have a database populating a TDBGrid in Delphi 2007 Pro. When the grid finishes populating, I want to automatically fill a list box based on data processed from the grid. I can do this manually by watching and waiting for the grid to completely fill with the dataset and then calling my next procedure. Is there an event that would allow calling the next procedure when the grid finishes populating automatically? Thanks.

+2  A: 

If you're using a TDataSet descendant, you can use its AfterOpen event:

"AfterOpen is called after the dataset establishes access to its data and the dataset is put into dsBrowse state."


edit (code sample for comments for Duilio's answer): In the below, 'CDS' is a 'TClientDataSet'. A 'TDBGrid' is also attached to the data set by means of a 'TDataSource', but the grid's functionality is not in any way effected by the code below, or the ListBox's functionality with the grid's for that matter..

procedure TForm1.CDSAfterOpen(DataSet: TDataSet);
var
  sl: TStringList;
begin
  sl := TStringList.Create;
  try
    sl.Sorted := True;
    sl.Duplicates := dupIgnore;

    DataSet.DisableControls;
    try
      DataSet.First;
      while not DataSet.Eof do begin
        sl.Add(DataSet.Fields[1].AsString);
        DataSet.Next;
      end;
      DataSet.First;
    finally
      DataSet.EnableControls;
    end;

    ListBox1.Items.Assign(sl);
  finally
    sl.Free;
  end;
end;
Sertac Akyuz
Correct, the DBGrid is a "window." I suspected I might have to work at the TDataSet level. AfterOpen triggers seconds before the TDBGrid is populated so it spawns an error. A TDBListBox is a great idea. What I do when the TDBGrid is finished filling all its rows from the database, I sort one of the fields in a string list: sl := TStringList.Create; sl.Sorted := True; sl.Duplicates := dupIgnore; and put that into an ordinary list box. I am not sure how I would do that with a TDBListBox. Thanks for the suggestions, I will try some things.
SteveJG
@Steve - 'AfterOpen' is *really* triggered when the DatSet's opening is complete. Make sure it's the DataSet linked to the DataSource of the Grid... Regarding a 'TDBListBox', unlike a DBGrid, it is not a control to be populated with data from multiple records. See its [documentation](http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devwin32/12ctrlsusingtdblistboxandtdbcombobox_xml.html).
Sertac Akyuz
Sertac, thank you. This code example does exactly what I need. The DBListBox populates correctly even before the DBGrid is finished populating, It still seems there is no way to know (other than by inspection), when the DBGrid finishes populating. Great work.
SteveJG
A: 

I think you could execute:

TDataSet.Open;
TDataSet.FetchAll;
{At this point DBGrid should be populated}

This will get all the data from your table. When done, your DBGrid should be populated.

Duilio Juan Isola
That might work to populate the grid. At the moment the dataset has about 6000 records, and requires about one second from opening to fill the DBGrid. I have no trouble filling the grid; what does not seem possible is to determine when the grid is populated and then execute another function upon completion, that is, execute the function as soon as the grid "knows" it is filled with the dataset. The DBGrid does not seem to have an event WhenFinishedPopulating from a dataset. Thank you for your idea, it just does not solve the problem.
SteveJG
@Steve - If you're not doing any `ProcessMessages` while retrieving your data, you might try posting a message to your form, like in [this answer](http://stackoverflow.com/questions/382527/delphi-app-initialization-best-practices-approach/382860#382860). You might also try deriving a 'TDBGrid' descendant and override its `LayoutChanged` together utilizing a global flag perhaps. *But* why/how is your code depend on the status of the grid?, how does the grid *process* data? If you need records they're in the dataset...
Sertac Akyuz
I temporarily solved the problem using a timer. Not ideal, but it does load the function I want loaded "automatically." The function I execute depends on the grid being fully populated..it can not work with incomplete data. The grid does NOT process any data, the function does. If I "need records they're in the data set" is true..I can easily copy all the field data I need into a DBListBox..I get a complete list, however, I do not want a complete list..I need a list with duplicates removed and "alphabetized."
SteveJG
My function takes the field of interest, loads it into a TStringList where I sort it and remove duplicates. I tried writing the function into the DBListBox events but could not get it to work, so for the moment, using a timer gets the job done; however it does not answer the original question...I assume it is not possible to do what I want to do with a standard DBGrid without writing my own control or accessing an application event handler.
SteveJG