简体   繁体   中英

How to avoid TDbgrid scrolling when returning to a previous location

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;

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.

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 MoveBy s. 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM