5

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.)

  Function TForm.DoSomethingToSelectedRows;
  var
    KeyAtStart: Integer;
  begin
    Result := TRUE;
    KeyAtStart := DataSet.FieldByName('Key').AsInteger;
    DataSet.DisableControls;
    DataSet.First;
    try
      while Result AND (NOT DataSet.EOF) do  DataSet
        begin
          if DBGrid1.SelectedRows.CurrentRowSelected then
            Result := ... do something ...
          fMPODataTls.GetDS.Next;
        end;
    finally
      DataSet.Locate('Key', KeyAtStart, []);    // re-position where we started
      DataSet.EnableControls;
    end;
  end;
RobertFrank
  • 7,332
  • 11
  • 53
  • 99
  • 2
    possible duplicate of [Delphi - restore actual row in DBGrid](http://stackoverflow.com/questions/2995662/delphi-restore-actual-row-in-dbgrid) – Sertac Akyuz Dec 22 '11 at 10:42
  • Thanks! This question is much more clear on what's being asked, which is evident from unrelated answers in the other question. So I guess keeping this question will be good.. – Sertac Akyuz Dec 22 '11 at 19:37

3 Answers3

2

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 Row and 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.

Community
  • 1
  • 1
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • I just implemented your solution and am very happy to see my grids no longer jumping around! Thanks again, Sertac. – RobertFrank Dec 22 '11 at 20:06
1

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.

Francesca
  • 21,452
  • 4
  • 49
  • 90
0

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.

Marcus Adams
  • 53,009
  • 9
  • 91
  • 143