Delphi - restore actual row in DBGrid
Asked Answered
M

4

5

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

Muoimuon answered 8/6, 2010 at 8:12 Comment(0)
N
10

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;
Nephograph answered 8/6, 2010 at 10:6 Comment(0)
C
1

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.

Con answered 8/6, 2010 at 8:30 Comment(2)
Hi! As I see not. GotoBookMark is same that Locate here, because we are after Open. But the actual grid row is not same, so Disable not prevent to Grid show the record in another position. MoveBy is good, but I need Locate here. But if I use locate, the Grid row changed... For example: the grind shown the record 127 in the row 4. When I reopen with moveby, it is also in row 4. When I use Locate/Bookmark, it is in 3, 2, 5 - randomly, where I can see the actual record... :-(Muoimuon
User 2 Insert/Delete a row, and your User 1's saved recordnumbers will be incorrect. That is what TOndrej is trying to help you avoid.Bateau
C
1

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;
Commensurate answered 8/6, 2010 at 9:0 Comment(2)
Hi! I use the routines like this: aRow = Grid.GetRow(); Query.ReOpen; SetActRow(aRow); So this is not bookmark problem, this is DBGrid Row problem...Muoimuon
What DBGrid are you using? Standard TDBGrid doesn't have property GetRow. I doubt that this is DBGrid problem. DBGrid's active record is the current active record in the dataset.Commensurate
P
0

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.

Poling answered 8/6, 2010 at 18:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.