Is it possible to get the row number that is displayed from the underlying dataset in the top-most row of a DBGrid, without that top-most row being the currently selected row, when the number of records in the underlying dataset is greater than the number of rows displayed in the DBGrid, and the DBGrid has been scrolled.

Here's my problem. From a drag/drop event handler attached to the DBGrid I can determine which visible row of the DBGrid the drop event is associated with using MyGrid.MouseCoord(X,Y).Y. When the underlying dataset contains less than or the same number of records as the number of rows displayed in the DBGrid, this value is also the row number of the associated record in the underlying dataset.

When the underlying dataset contains more records than the number of visible rows in the DBGrid, MyGrid.MouseCoord(X, Y).Y and TDataSet(MyGrid.DataSource.DataSet).RecNo are the same only when the first row of the dataset appears on the first row of the grid.

Is there some way to identify the record number in the underlying dataset (or the offset) of the top-most displayed record in a DBGrid without that DBGrid row being selected? I know that if I actually select the top-most row of the DBGrid then I can use TDataSet(MyGrid.DataSource.DataSet).RecNo to get the current record number of the underlying dataset. However, from DBGrid.OnDragOver or DBGrid.OnDragDrop events I only have a reference to the DBGrid and the mouse coordinates (from which I can determine which row of the grid was the target of the drop).

For example, if I can determine that the DBGrid is displaying the third record in the underlying dataset in the top-most row of the grid, my problem is solved. Likewise, if I can read an underlying TField of a particular row (say, the top-most row) without that row being select, I have what I need. However, I cannot see a way to do this.

Any suggestions will be greatly appreciated.

Edit: I previously posted a blog about dragging and dropping into a DBGrid. With this new info, I can solve a previously known problem. I will be updating that blog sometime this week, and will add a link to that blog here once I have done so.

There is an additional issue. When the number of visible rows is less than the number of underlying records, we need to also accomdate calculating the drop when it occurs after the last visible row. When dropping after the last visible row, MouseCoord(x,y).Y returns -1.

Here is a modification to Uwe's code that accomplishes that end:

function TDBGridHelper.RecNoFromVisibleRow(Value: Integer): Integer;
begin
  if Value = -1 then
  begin
    Result := DataSource.DataSet.RecNo - Row + TopRow + VisibleRowCount
  end
  else
  begin
    Result := DataSource.DataSet.RecNo - Row + TopRow + Value;
    if dgTitles in Options then
      Dec(Result);
  end;
end;

Edit: As I mentioned in the original question, I was interested in this answer in order to fix a behavior in my code that implements drag and drop into a DBGRid. With this answer I have updated my drag and drop behavior, and I have written about this update in my blog. You can find this discussion, including links to the original blog post, at the following URL: Dragging and Dropping into a DBGrid Revisited

1

There are 1 answers

7
Uwe Raabe On BEST ANSWER

As long as there is only an offset between DataSet.RecNo and the visible rownumber in the grid, you might get the required information from the protected members Row and TopRow, which can be accessed by a class helper. Something like this:

function TDbGridHelper.RecNoFromVisibleRow(Value: Integer): Integer;
begin
  Result := DataSource.DataSet.RecNo - Row + TopRow + Value;
  if dgTitles in Options then
    Dec(Result);
end;