This answer is intended as a minor supplement to Mason's, not an alternative. I've added it only because another answer has appeared, suggesting, incorrectly imo, the use of the dataset's RecNo property. Not all TDataSet descendants implement RecNo reliably or at all. Some descendants just return a constant value e.g. 0 for the current rows's RecNo and do nothing when you assign a value to it.
procedure TMyForm.DoSomethingWithDataSet(ADataSet : TDataSet);
var
Bookmark : TBookmark;
begin
Bookmark := ADataSet.GetBookmark; // Save your place in ADataSet
try
Screen.Cursor := crSqlWait; // Show the user that something is happening
Update; // update the form to make sure screen cursor updates
ADataSet.DisableControls;
// do something with ADataSet here e.g.
ADataSet.First;
while not ADataSet.Eof do begin
// do something with current row here, then
ADataSet.Next;
end;
finally
ADataSet.GotoBookmark(Bookmark); // Return to where you were at outset
ADataSet.FreeBookmark(Bookmark);
ADataSet.EnableControls;
Screen.Cursor := crDefault; // Let the user see you're done
end;
end;