In the code below, we do some operations (not deletions) on some selected rows.
However, sometimes, when finished, the top selected row has scrolled so that it is displayed 1/2 way down the grid. Is there a way to avoid this scrolling? (If my code to traverse the selected row below is improper for some unrelated reason, I welcome corrections.)
Result := TRUE;
KeyAtStart := DataSet.FieldByName('Key').AsInteger;
while Result AND (NOT DataSet.EOF) do DataSet
if DBGrid1.SelectedRows.CurrentRowSelected then
Result := ... do something ...
DataSet.Locate('Key', KeyAtStart, ); // re-position where we started
Before looping through the dataset, you can keep note of the top row that the grid is displaying and the number of total records that is displayed. With this information, after you relocate the record, you can position the record to the exact row by moving either to the top or to the bottom and then moving back again.
You can carry out the moving by
MoveBys. Unfortunately the
RowCount properties of
TDBGrid is protected, for that you have to use what is widely known as 'protected hack'.
There's code example in this answer, together with checking bookmarks, so that you don't end up on a wrong record.
There is no guarantee that the current record in your grid is exactly positioned at the center of the visible rows, but doing a Locate when it has scrolled out of sight will make it (the new current record) the middle row of the grid, hence the apparent scrolling.
If you want to re-position the grid as it was, you have to memorize which record is at the top row.
If you are using a TClientDataset, you don't have to mess with the user's cursor, you can clone it and do your edits there.
If I have DBGrid1 linked to ClientDataSet1, and I have the cursor on row 5 of the DBGrid (and the ClientDataSet) and within view of the the first row, and delete the first row using a cloned cursor like below, I'd see the first row disappear and my selected row would go up by one row height.
Function TForm.DeleteFirstRow; var myCDS: TClientDataSet; begin myCDS := myCDS.Create(nil); try myCDS.CloneCursor(ClientDataSet1, False); myCDS.First; myCDS.Delete; finally myCDS.Free; end;
If I was scrolled all the way down to row 500 or so, out of view of the first row, and executed it again, the selected row would not move at all in the grid.