Delphi - 恢复 DBGrid 中的实际行

发布于 2024-09-04 06:39:20 字数 1107 浏览 6 评论 0原文

D6 教授

以前我们使用DBISAM 和DBISAMTable。它处理 RecNo,并且可以很好地进行修改(删除、编辑等)。

现在我们用 ElevateDB 代替,它不处理 RecNo,而且很多时候我们使用查询,而不是表。

必须重新打开查询才能看到修改。

但是如果我们重新打开查询,我们需要重新定位到最后一条记录。 定位是不够的,因为网格将其显示在另一行中。 这是非常令人不安的事情,因为当修改记录移动到另一行后,你很难跟上它,而用户讨厌这样。

我们找到了这段代码:

function TBaseDBGrid.GetActRow: integer;
begin
 Result := -1 + Row;
end;


procedure TBasepDBGrid.SetActRow(aRow: integer);
var
 bm : TBookMark;
begin
 if IsDataSourceValid(DataSource) then with DataSource.DataSet do begin
  bm := GetBookmark;
  DisableControls;
  try
   MoveBy(-aRow);
   MoveBy(aRow);
   //GotoBookmark(bm);
  finally
   FreebookMark(bm);
   EnableControls;
  end;
 end;
end;

原来的例子是使用moveby。这对于查询来说效果很好,因为我们看不到查询在后台重新打开,视觉控制没有改变行位置。

但是,当我们有 EDBTable 或实时/敏感查询时,使用 MoveBy 是危险的,因为如果有人删除或追加新行,我们可能会重新定位到错误的记录。

然后我尝试使用书签(见备注)。但这种技术不起作用,因为它在另一个行位置显示记录...

所以问题是:如何在 DBGrid 中强制行位置和记录?

或者什么样的DBGrid可以在底层DataSet刷新后重新定位到记录/行?

我寻找用户友好的解决方案,我理解它们,因为我尝试使用这种跨 DBGrid 的跳转,但使用起来非常糟糕,因为当我尝试在更新后查找原始记录时,我的眼睛都快要出来了...:-(

谢谢对于您的每一个帮助、链接、信息: DD

D6 prof.

Formerly we used DBISAM and DBISAMTable. That handle the RecNo, and it is working good with modifications (Delete, edit, etc).

Now we replaced with ElevateDB, that don't handle RecNo, and many times we use Queries, not Tables.

Query must reopen to see the modifications.

But if we Reopen the Query, we need to repositioning to the last record.
Locate isn't enough, because Grid is show it in another Row.
This is very disturbing thing, because after the modification record is moving into another row, you hard to follow it, and users hate this.

We found this code:

function TBaseDBGrid.GetActRow: integer;
begin
 Result := -1 + Row;
end;


procedure TBasepDBGrid.SetActRow(aRow: integer);
var
 bm : TBookMark;
begin
 if IsDataSourceValid(DataSource) then with DataSource.DataSet do begin
  bm := GetBookmark;
  DisableControls;
  try
   MoveBy(-aRow);
   MoveBy(aRow);
   //GotoBookmark(bm);
  finally
   FreebookMark(bm);
   EnableControls;
  end;
 end;
end;

The original example is uses moveby. This working good with Queries, because we cannot see that Query reopened in the background, the visual control is not changed the row position.

But when we have EDBTable, or Live/Sensitive Query, the MoveBy is dangerous to use, because if somebody delete or append a new row, we can relocate into wrong record.

Then I tried to use the BookMark (see remark). But this technique isn't working, because it is show the record in another Row position...

So the question: how to force both the row position and record in DBGrid?

Or what kind of DBGrid can relocate to the record/row after the underlying DataSet refreshed?

I search for user friendly solution, I understand them, because I tried to use this jump-across DBGrid, and very bad to use, because my eyes are getting out when try to find the original record after update... :-(

Thanks for your every help, link, info:
dd

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

娇纵 2024-09-11 06:39:20

既然“MoveBy”正在为您工作,请使用它们。

在关闭数据集之前获取“书签”。完成您的工作,重新打开数据集,然后使用“MoveBy”在网格上重新定位您的记录。完成后,获取另一个书签并使用 DataSet.CompareBookmarks 将其与前一个书签进行比较。如果结果为 0 则很好,如果不是,则仅对前一个书签发出“GotoBookmark”。

这样,只要其他用户没有删除/插入记录,您的网格就不会显得跳跃,如果不是这种情况,至少您会在同一条记录上。


编辑:下面是一些代码示例,即使数据集中存在删除/插入操作,也应将所选记录重新定位到正确的位置。请注意,为了简单起见,代码省略了禁用/启用控件,以及填充网格的记录较少时的特殊情况。

type
  TAccessDBGrid = class(TDBGrid);

procedure TForm1.Button1Click(Sender: TObject);
var
  BmSave, Bm: TBookmark;
  GridRow, TotalRow: Integer;
begin
  GridRow := TAccessDBGrid(DBGrid1).Row;
  TotalRow := TAccessDBGrid(DBGrid1).RowCount;
  BmSave := DBGrid1.DataSource.DataSet.GetBookmark;
  try

    // close dataset, open dataset...

    if DBGrid1.DataSource.DataSet.BookmarkValid(BmSave) then
      DBGrid1.DataSource.DataSet.GotoBookmark(BmSave);
    Dec(TotalRow);
    if GridRow < TotalRow div 2 then begin
      DBGrid1.DataSource.DataSet.MoveBy(TotalRow - GridRow);
      DBGrid1.DataSource.DataSet.MoveBy(GridRow - TotalRow);
    end else begin
      if dgTitles in DBGrid1.Options then
        Dec(GridRow);
      DBGrid1.DataSource.DataSet.MoveBy(-GridRow);
      DBGrid1.DataSource.DataSet.MoveBy(GridRow);
    end;
    Bm := DBGrid1.DataSource.DataSet.GetBookmark;
    try
      if (DBGrid1.DataSource.DataSet.BookmarkValid(Bm) and
          DBGrid1.DataSource.DataSet.BookmarkValid(BmSave)) and
          (DBGrid1.DataSource.DataSet.CompareBookmarks(Bm, BmSave) <> 0) then
        DBGrid1.DataSource.DataSet.GotoBookmark(BmSave);
    finally
      DBGrid1.DataSource.DataSet.FreeBookmark(Bm);
    end;
  finally
    DBGrid1.DataSource.DataSet.FreeBookmark(BmSave);
  end;
end;

Since 'MoveBy's are working for you, use them.

Get a 'Bookmark' before closing the dataset. Do your work, reopen the dataset and then reposition your record on the grid with 'MoveBy's. When you're done, get another Bookmark and compare it with the previous one with DataSet.CompareBookmarks. If the result is 0 fine, if not, only then issue a 'GotoBookmark' for the previous bookmark.

This way, as long as another user have not deleted/inserted records your grid will not seem to be jumpy, and if this is not the case at least you'd be on the same record.


edit: Here's some code sample that should reposition the selected record in the correct place even when there had been deletes/inserts in the dataset. Note that the code omits disabling/enabling controls, and the special case when there are less records to fill the grid for simplicity.

type
  TAccessDBGrid = class(TDBGrid);

procedure TForm1.Button1Click(Sender: TObject);
var
  BmSave, Bm: TBookmark;
  GridRow, TotalRow: Integer;
begin
  GridRow := TAccessDBGrid(DBGrid1).Row;
  TotalRow := TAccessDBGrid(DBGrid1).RowCount;
  BmSave := DBGrid1.DataSource.DataSet.GetBookmark;
  try

    // close dataset, open dataset...

    if DBGrid1.DataSource.DataSet.BookmarkValid(BmSave) then
      DBGrid1.DataSource.DataSet.GotoBookmark(BmSave);
    Dec(TotalRow);
    if GridRow < TotalRow div 2 then begin
      DBGrid1.DataSource.DataSet.MoveBy(TotalRow - GridRow);
      DBGrid1.DataSource.DataSet.MoveBy(GridRow - TotalRow);
    end else begin
      if dgTitles in DBGrid1.Options then
        Dec(GridRow);
      DBGrid1.DataSource.DataSet.MoveBy(-GridRow);
      DBGrid1.DataSource.DataSet.MoveBy(GridRow);
    end;
    Bm := DBGrid1.DataSource.DataSet.GetBookmark;
    try
      if (DBGrid1.DataSource.DataSet.BookmarkValid(Bm) and
          DBGrid1.DataSource.DataSet.BookmarkValid(BmSave)) and
          (DBGrid1.DataSource.DataSet.CompareBookmarks(Bm, BmSave) <> 0) then
        DBGrid1.DataSource.DataSet.GotoBookmark(BmSave);
    finally
      DBGrid1.DataSource.DataSet.FreeBookmark(Bm);
    end;
  finally
    DBGrid1.DataSource.DataSet.FreeBookmark(BmSave);
  end;
end;
月亮坠入山谷 2024-09-11 06:39:20

在关闭并重新打开查询之前存储唯一关键字段的值,然后在重新打开后定位到记录。 DisableControls/EnableControls 以防止屏幕更新。

Store the value(s) of your unique key field(s) before closing and reopening the query, then Locate to the record after reopening. DisableControls/EnableControls to prevent screen updates.

梦亿 2024-09-11 06:39:20

我脑海中浮现的只是一段简单的代码:

procedure DoRefresh(Dataset: TDataset);
var
  bkm: TBookmark;
begin
  Dataset.UpdateCursorPos;
  bkm := Dataset.GetBookmark;
  Dataset.DisableControls;
  try
    Dataset.Refresh;  //refresh dataset if it's open

    if Dataset.BookmarkValid(bkm) then
    begin
      Dataset.GotoBookmark(bkm);
    end;
  finally
    Dataset.EnableControls;
    Dataset.FreeBookmark(bkm);
  end;
end;

Just simple piece of code that came in my mind:

procedure DoRefresh(Dataset: TDataset);
var
  bkm: TBookmark;
begin
  Dataset.UpdateCursorPos;
  bkm := Dataset.GetBookmark;
  Dataset.DisableControls;
  try
    Dataset.Refresh;  //refresh dataset if it's open

    if Dataset.BookmarkValid(bkm) then
    begin
      Dataset.GotoBookmark(bkm);
    end;
  finally
    Dataset.EnableControls;
    Dataset.FreeBookmark(bkm);
  end;
end;
同展鸳鸯锦 2024-09-11 06:39:20

记录位置很大程度上取决于从查询/表对象获得的结果集的排序顺序。
如果您根本不排序,则从服务器获取的顺序是实现定义的,因此无法保证重新打开查询时记录的顺序相同,即使没有发生任何更改 。至少在 MSSQL 和 Firebird 中,如果不使用 Order By 子句,结果的顺序会有所不同。

至于重新定位,我认为 TOndrej 解决方案是最安全的解决方案 - 使用结果集的主键将网格重新定位在正确的记录上。

Record position depends much on the sort order of resultset you got from the Query/Table object.
If you don't order at all, the order you get from the server is implementation defined and such, can't guarantee that records come in the same order when reopen the query, even if no changes happened. At least in MSSQL and Firebird, results come in different orders if no Order By clause is used.

As for repositioning, I think that TOndrej solution is the safest one - using the primary key of your resultset to reposition the grid on the right record.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文