What dataset row appears in the top-most row of DBGrid when RowCount > VisibleRowCount without that first row of the grid being selected?
Asked Answered
F

1

8

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

Floccule answered 3/8, 2013 at 14:46 Comment(0)
C
8

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;
Conative answered 3/8, 2013 at 15:30 Comment(7)
Uwe, thank you for your input. Row gives me the visible row number that is current in the grid, and TopRow always gives me 1, even when the DBGrid is scrolled to a point where the first row in the underlying dataset does not appear as the first row in the grid. Furthermore, RecNo of the DataSet is the current record, and may not be the record where the drag/drop occurred. I'm looking for something like this: if the grid is scrolled so that the third record in the dataset appears in the first visible row of the grid, I can read a property that returns 3 (or 2 if zero-based).Floccule
Another acceptable solution would be to be able to read values from columns associated with the first visible row in dbgrid without that row being the current row in the grid (or the first record in the underlying dataset).Floccule
Perhaps I still don't understand the problem. The function should return the RecNo of the record shown in the row number Value. I tried with the MouseOver event using MouseCoord().Y and it worked as expected.Conative
Well, you certainly are correct. Your function correctly calcuates the position of the record at MouseCoord(x,y).Y within the grid, regardless of the scroll position of the grid. I think what threw me was the RecNo of the DataSet. Somehow I convinced myself that the DataSet might not point to a record in the viewable area of the grid. That, however, is impossible, as the grid by definition will always display the current record in the viewable area. Thanks again for your help and insight.Floccule
Been playing with this. It works great, except under one condition. If the grid is larger than visible rows, and the drop occurs after the last row, RecNoFromVisibleRow returns 0, instead of -1. So far, I can get around that by calling RecNoFromVisibleRow when MouseCoord(x,y).y does not return -1, and everything works great. When -1 is returned, I know that I am dropping at the end of the table.Floccule
That may be related to the fact that RecNo on ClientDataSets is 1-based. So the -1 transforms to 0. BTW, your CDS book is always a valuable helper for me. Kudos!Conative
Uwe: Actually, the -1 is the value that MouseCoord(x,y).Y returns when you click below the last record in a DBGrid. Nonetheless, your answer was instrumental in helping me finalize my drag/drop code. I have updated my question above to include a link to the relevant blog post. Also, thank you for your nice comment about Delphi in Depth: ClientDataSets. Best Regards.Floccule

© 2022 - 2024 — McMap. All rights reserved.