Delphi - восстановить фактическую строку в DBGrid

Д6 проф.

Раньше мы использовали 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, и очень плохо использовать, потому что мои глаза вылезают, когда я пытаюсь найти исходную запись после обновления... :-(

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


person durumdara    schedule 08.06.2010    source источник


Ответы (4)


Поскольку 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;
person Sertac Akyuz    schedule 08.06.2010

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

person Ondrej Kelle    schedule 08.06.2010
comment
Привет! Как я вижу нет. GotoBookMark — это то же самое, что Locate здесь, потому что мы после Open. Но фактическая строка сетки не такая же, поэтому Disable не мешает сетке отображать запись в другом месте. MoveBy хорош, но мне нужно Locate здесь. Но если я использую локацию, строка сетки меняется... Например: гринд показал запись 127 в 4-й строке. Когда я снова открываю с помощью moveby, она также находится в 4-й строке. Когда я использую локацию/закладку, она находится в 4-й строке. 3, 2, 5 - случайным образом, где я могу увидеть актуальную запись... :-( - person durumdara; 08.06.2010
comment
Пользователь 2 Вставляет/удаляет строку, и сохраненные номера записей пользователя 1 будут неверными. Это то, чего TOndrej пытается помочь вам избежать. - person Warren P; 11.06.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;
person Linas    schedule 08.06.2010
comment
Привет! Я использую такие подпрограммы: aRow = Grid.GetRow(); Запрос.Повторно открыть; SetActRow(aRow); Так что это не проблема с закладками, это проблема DBGrid Row... - person durumdara; 08.06.2010
comment
Какой DBGrid вы используете? Стандартный TDBGrid не имеет свойства GetRow. Я сомневаюсь, что это проблема DBGrid. Активная запись DBGrid — это текущая активная запись в наборе данных. - person Linas; 08.06.2010

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

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

person Fabricio Araujo    schedule 08.06.2010