Delphi - восстановить актуальную строку в DBGrid - PullRequest
5 голосов
/ 08 июня 2010

D6 проф.

Ранее мы использовали DBISAM и DBISAMTable. Это обрабатывает RecNo, и он хорошо работает с изменениями (удаление, редактирование и т. Д.).

Теперь мы заменили на ElevateDB, который не обрабатывает RecNo, и много раз мы используем запросы, а не таблицы.

Запрос должен быть открыт заново, чтобы увидеть изменения.

Но если мы снова откроем запрос, нам нужно изменить положение к последней записи. Определить местоположение недостаточно, потому что 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. Это хорошо работает с запросами, потому что мы не видим, что запрос снова открывается в фоновом режиме, визуальный элемент управления не меняет положение строки.

Но когда у нас есть EDBTable или Live / Sensitive Query, MoveBy опасно использовать, потому что если кто-то удалит или добавит новую строку, мы можем переместиться в неправильную запись.

Затем я попытался использовать BookMark (см. Примечание). Но этот метод не работает, потому что он показывает запись в другой позиции строки ...

Итак, вопрос: как заставить положение строки и запись в DBGrid?

Или какой DBGrid можно переместить в запись / строку после обновления базового набора данных?

Я ищу удобное для пользователя решение, я понимаю его, потому что я пытался использовать этот переход через DBGrid, и очень плохо в использовании, потому что у меня вылезают глаза, когда я пытаюсь найти оригинальную запись после обновления ...: - (

Спасибо за вашу помощь, ссылку, информацию: дд

Ответы [ 4 ]

8 голосов
/ 08 июня 2010

Поскольку MoveBy's работают на вас, используйте их.

Получите «Закладку» перед закрытием набора данных.Сделайте свою работу, заново откройте набор данных и затем переместите свою запись в сетку с помощью MoveBy's.Когда вы закончите, получите другую закладку и сравните ее с предыдущей с помощью DataSet.CompareBookmarks.Если результат равен 0, если нет, только тогда введите 'GotoBookmark' для предыдущей закладки.

Таким образом, до тех пор, пока другой пользователь не удалит / вставит записи, ваша сетка не будет выглядеть нервной, и если это не так, по крайней мере, вы будете на той же записи.


edit: Вот пример кода, который должен переместить выбранную запись в правильное место, даже если в наборе данных были удалены / вставлены.Обратите внимание, что в коде пропущено отключение / включение элементов управления, а также особый случай, когда имеется меньше записей для заполнения сетки для простоты.

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 голос
/ 08 июня 2010

Сохраните значения вашего уникального ключевого поля перед закрытием и повторным открытием запроса, затем Locate для записи после повторного открытия.DisableControls / EnableControls для предотвращения обновления экрана.

0 голосов
/ 08 июня 2010

Позиция записи во многом зависит от порядка сортировки набора результатов, который вы получили от объекта Query / Table.Если вы вообще не заказываете, порядок, который вы получаете с сервера, определяется реализацией и поэтому не может гарантировать, что записи поступают в том же порядке при повторном открытии запроса, , даже если никаких изменений не произошло .По крайней мере, в MSSQL и Firebird результаты приходят в разных порядках, если не используется предложение Order By .

Что касается репозиции, я думаю, что решение TOndrej является наиболее безопасным - использование первичного ключавашего набора результатов, чтобы переместить сетку на нужную запись.

0 голосов
/ 08 июня 2010

Просто кусок кода, который мне пришёл в голову:

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;
...