D6教授。
以前我们使用过DBISAM和DBISAMTable。它处理RecNo,它可以很好地修改(删除,编辑等)。
现在我们替换了不处理RecNo的ElevateDB,很多时候我们使用Queries而不是Tables。
必须重新打开查询以查看修改。
但是如果我们重新打开查询,我们需要重新定位到最后一条记录。 定位是不够的,因为Grid在另一行中显示它。 这是非常令人不安的事情,因为在修改记录进入另一行之后,你很难遵循它,并且用户讨厌这个。
我们找到了这段代码:
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。这与Queries工作正常,因为我们无法看到Query在后台重新打开,可视控件没有改变行位置。
但是当我们有EDBTable或Live / Sensitive Query时,MoveBy使用起来很危险,因为如果有人删除或追加新行,我们可以重新定位到错误的记录中。
然后我尝试使用BookMark(见注释)。但是这种技术不起作用,因为它在另一个Row位置显示记录......
所以问题:如何在DBGrid中强制行位置和记录?
或者,在基础DataSet刷新后,哪种DBGrid可以重定位到记录/行?
我搜索用户友好的解决方案,我理解它们,因为我试图使用这种跳过DBGrid,并且使用起来非常糟糕,因为在更新后尝试查找原始记录时我的眼睛出来了......: - (
感谢您的帮助,链接,信息: DD
答案 0 :(得分:8)
因为'MoveBy'正在为你工作,所以请使用它们。
在关闭数据集之前获取“书签”。做你的工作,重新打开数据集,然后用'MoveBy'重新定位你在网格上的记录。完成后,获取另一个书签,并将其与之前的Bookmark与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;
答案 1 :(得分:1)
在关闭并重新打开查询之前存储唯一键字段的值,然后在重新打开后将Locate
存储到记录中。 DisableControls
/ EnableControls
以阻止屏幕更新。
答案 2 :(得分:0)
我想到的只是一段简单的代码:
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;
答案 3 :(得分:0)
记录位置在很大程度上取决于从Query / Table对象获得的结果集的排序顺序。 如果您根本没有订购,那么您从服务器获得的订单是实现定义的,并且不能保证重新打开查询时记录的顺序相同,即使没有发生任何更改 。至少在MSSQL和Firebird中,如果没有使用 Order By 子句,结果会有不同的顺序。
至于重新定位,我认为TOndrej解决方案是最安全的 - 使用结果集的主键在正确的记录中重新定位网格。