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, и очень плохо в использовании, потому что у меня вылезают глаза, когда я пытаюсь найти оригинальную запись после обновления...:-(
Спасибо за вашу помощь, ссылку, информацию: дд
4 ответа
Поскольку MoveBy's работают на вас, используйте их.
Получите закладку перед закрытием набора данных. Сделайте свою работу, заново откройте набор данных и затем переместите свою запись в сетку с помощью MoveBy's. Когда вы закончите, получите другую закладку и сравните ее с предыдущей с помощью 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;
Сохраните значения вашего уникального ключевого поля перед закрытием и повторным открытием запроса, затем Locate
на запись после повторного открытия. DisableControls
/EnableControls
чтобы предотвратить обновления экрана.
Просто простой кусок кода, который пришел мне в голову:
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;
Позиция записи во многом зависит от порядка сортировки набора результатов, который вы получили от объекта Query/Table. Если вы вообще не заказываете, порядок, который вы получаете с сервера, определяется реализацией и поэтому не может гарантировать, что записи поступают в том же порядке при повторном открытии запроса, даже если никаких изменений не произошло. По крайней мере, в MSSQL и Firebird результаты приходят в разных порядках, если не используется предложение Order By.
Что касается репозиции, я думаю, что решение TOndrej является наиболее безопасным - использование первичного ключа вашего набора результатов для изменения положения сетки на нужной записи.