delphi 根据 ID 定位选中 DBGrid 记录
在 Delphi 中根据 ID 定位并选中 DBGrid 中的记录,有多种实现方式。以下是完整的解决方案:
🎯 核心方法
方法 1:使用 Locate 定位记录(最常用)
pascal
procedure TForm1.LocateRecordByID(const ID: Integer);begin
if DataSource1.DataSet.Active then
begin
// Locate 方法:查找 ID 字段等于指定值的记录
if DataSource1.DataSet.Locate('ID', ID, []) then
begin
// 记录已被定位,DBGrid 会自动滚动到该记录并选中
ShowMessage('已定位到 ID: ' + IntToStr(ID));
end
else
begin
ShowMessage('未找到 ID 为 ' + IntToStr(ID) + ' 的记录');
end;
end;end;// 使用示例procedure TForm1.ButtonLocateClick(Sender: TObject);var
SearchID: Integer;begin
SearchID := StrToIntDef(EditID.Text, 0);
if SearchID > 0 then
LocateRecordByID(SearchID);end;
方法 2:使用 FindKey 或 FindNearest(适用于 TTable/TClientDataSet)
pascal
procedure TForm1.FindRecordByID(const ID: Integer);begin
if Table1.Active then
begin
// 需要先设置索引字段
Table1.IndexFieldNames := 'ID';
// FindKey 返回 Boolean,成功则定位到记录
if Table1.FindKey([ID]) then
begin
// 定位成功,DBGrid 自动滚动到该记录
ShowMessage('找到记录,ID: ' + IntToStr(ID));
end
else
begin
ShowMessage('未找到记录');
end;
end;end;
方法 3:使用 Filter 过滤并定位(适用于大数据量)
pascal
procedure TForm1.FilterAndLocate(const ID: Integer);begin
if DataSource1.DataSet.Active then
begin
// 临时禁用控件更新,提高性能
DataSource1.DataSet.DisableControls;
try
// 应用过滤器
DataSource1.DataSet.Filter := 'ID = ' + IntToStr(ID);
DataSource1.DataSet.Filtered := True;
if not DataSource1.DataSet.IsEmpty then
begin
// 定位到第一条(也是唯一一条)记录
DataSource1.DataSet.First;
ShowMessage('已定位到 ID: ' + IntToStr(ID));
end
else
begin
ShowMessage('未找到记录');
// 清除过滤器
DataSource1.DataSet.Filtered := False;
end;
finally
DataSource1.DataSet.EnableControls;
end;
end;end;
方法 4:使用 Bookmark 精确滚动并高亮显示
pascal
procedure TForm1.LocateAndHighlightByID(const ID: Integer);var
Bookmark: TBookmark;
Found: Boolean;begin
if not DataSource1.DataSet.Active then Exit;
Found := DataSource1.DataSet.Locate('ID', ID, []);
if Found then
begin
// 保存书签
Bookmark := DataSource1.DataSet.GetBookmark;
try
// 确保 DBGrid 滚动到该记录
DBGrid1.SelectedRows.Clear; // 清除其他选中状态
DBGrid1.SelectedRows.CurrentRowSelected := True;
// 可选:滚动到可视区域
DBGrid1.DataSource.DataSet.GotoBookmark(Bookmark);
ShowMessage('已定位并选中 ID: ' + IntToStr(ID));
finally
DataSource1.DataSet.FreeBookmark(Bookmark);
end;
end
else
begin
ShowMessage('未找到 ID 为 ' + IntToStr(ID) + ' 的记录');
end;end;
📋 完整示例代码
pascal
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DBGrids, DB, ADODB, StdCtrls, Grids, ExtCtrls;type
TForm1 = class(TForm)
DBGrid1: TDBGrid;
DataSource1: TDataSource;
ADOQuery1: TADOQuery;
Panel1: TPanel;
EditID: TEdit;
ButtonLocate: TButton;
ButtonFindKey: TButton;
ButtonFilter: TButton;
ButtonGoto: TButton;
Label1: TLabel;
procedure ButtonLocateClick(Sender: TObject);
procedure ButtonFindKeyClick(Sender: TObject);
procedure ButtonFilterClick(Sender: TObject);
procedure ButtonGotoClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
private
FCurrentID: Integer;
procedure LocateByLocate(const ID: Integer);
procedure LocateByFindKey(const ID: Integer);
procedure LocateByFilter(const ID: Integer);
procedure LocateByGoto(const ID: Integer);
procedure HighlightCurrentRow;
public
{ Public declarations }
end;var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.FormCreate(Sender: TObject);begin
// 打开数据集
ADOQuery1.SQL.Text := 'SELECT ID, Name, Age, Department FROM Employees ORDER BY ID';
ADOQuery1.Open;
// 设置 DBGrid 属性
DBGrid1.Options := DBGrid1.Options + [dgRowSelect, dgAlwaysShowSelection];
DBGrid1.Options := DBGrid1.Options - [dgMultiSelect]; // 单选模式end;// 方法1: 使用 Locate(推荐)procedure TForm1.LocateByLocate(const ID: Integer);begin
if ADOQuery1.Active then
begin
// Locate 支持查找字符串、整数、浮点数等
if ADOQuery1.Locate('ID', ID, []) then
begin
ShowMessage(Format('✓ 已定位到记录 ID=%d', [ID]));
FCurrentID := ID;
end
else
begin
ShowMessage(Format('✗ 未找到 ID=%d 的记录', [ID]));
end;
end;end;// 方法2: 使用 FindKey(需要索引支持)procedure TForm1.LocateByFindKey(const ID: Integer);begin
if ADOQuery1.Active then
begin
// ADO 的 FindKey 需要先设置排序
ADOQuery1.Sort := 'ID';
if ADOQuery1.FindFirst('ID = ' + IntToStr(ID)) then
begin
ShowMessage(Format('✓ FindKey 定位到 ID=%d', [ID]));
FCurrentID := ID;
end
else
begin
ShowMessage(Format('✗ FindKey 未找到 ID=%d', [ID]));
end;
end;end;// 方法3: 使用 Filter 过滤procedure TForm1.LocateByFilter(const ID: Integer);var
OldFilter: string;
OldFiltered: Boolean;begin
if ADOQuery1.Active then
begin
// 保存原有过滤状态
OldFilter := ADOQuery1.Filter;
OldFiltered := ADOQuery1.Filtered;
ADOQuery1.DisableControls;
try
// 设置新过滤器
ADOQuery1.Filter := 'ID = ' + IntToStr(ID);
ADOQuery1.Filtered := True;
if not ADOQuery1.IsEmpty then
begin
ADOQuery1.First;
ShowMessage(Format('✓ Filter 定位到 ID=%d', [ID]));
FCurrentID := ID;
end
else
begin
ShowMessage(Format('✗ Filter 未找到 ID=%d', [ID]));
// 恢复原过滤状态
ADOQuery1.Filter := OldFilter;
ADOQuery1.Filtered := OldFiltered;
end;
finally
ADOQuery1.EnableControls;
end;
end;end;// 方法4: 使用 Goto(通过书签)procedure TForm1.LocateByGoto(const ID: Integer);var
Bookmark: TBookmark;
Found: Boolean;begin
if not ADOQuery1.Active then Exit;
Found := False;
ADOQuery1.DisableControls;
try
ADOQuery1.First;
while not ADOQuery1.Eof do
begin
if ADOQuery1.FieldByName('ID').AsInteger = ID then
begin
Found := True;
Break;
end;
ADOQuery1.Next;
end;
if Found then
begin
Bookmark := ADOQuery1.GetBookmark;
try
// 确保记录在 DBGrid 中可见
DBGrid1.SelectedRows.Clear;
DBGrid1.DataSource.DataSet.GotoBookmark(Bookmark);
// 可选:滚动到可视区域
DBGrid1.SetFocus;
ShowMessage(Format('✓ Goto 定位到 ID=%d', [ID]));
FCurrentID := ID;
finally
ADOQuery1.FreeBookmark(Bookmark);
end;
end
else
begin
ShowMessage(Format('✗ Goto 未找到 ID=%d', [ID]));
end;
finally
ADOQuery1.EnableControls;
end;end;// 高亮当前选中行procedure TForm1.HighlightCurrentRow;begin
// 刷新 DBGrid 以重新绘制
DBGrid1.Invalidate;end;// DBGrid 自定义绘制(高亮选中的行)procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);begin
// 如果是当前选中的记录,高亮显示
if gdSelected in State then
begin
DBGrid1.Canvas.Brush.Color := clHighlight;
DBGrid1.Canvas.Font.Color := clHighlightText;
end
else
begin
DBGrid1.Canvas.Brush.Color := clWindow;
DBGrid1.Canvas.Font.Color := clWindowText;
end;
// 绘制单元格
DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State);end;// 按钮事件:使用 Locateprocedure TForm1.ButtonLocateClick(Sender: TObject);var
ID: Integer;begin
ID := StrToIntDef(EditID.Text, 0);
if ID > 0 then
LocateByLocate(ID)
else
ShowMessage('请输入有效的 ID');end;// 按钮事件:使用 FindKeyprocedure TForm1.ButtonFindKeyClick(Sender: TObject);var
ID: Integer;begin
ID := StrToIntDef(EditID.Text, 0);
if ID > 0 then
LocateByFindKey(ID)
else
ShowMessage('请输入有效的 ID');end;// 按钮事件:使用 Filterprocedure TForm1.ButtonFilterClick(Sender: TObject);var
ID: Integer;begin
ID := StrToIntDef(EditID.Text, 0);
if ID > 0 then
LocateByFilter(ID)
else
ShowMessage('请输入有效的 ID');end;// 按钮事件:使用 Gotoprocedure TForm1.ButtonGotoClick(Sender: TObject);var
ID: Integer;begin
ID := StrToIntDef(EditID.Text, 0);
if ID > 0 then
LocateByGoto(ID)
else
ShowMessage('请输入有效的 ID');end;end.
🔧 高级技巧
1. 带搜索选项的 Locate
pascal
procedure TForm1.AdvancedLocate(const ID: Integer);const
// Locate 选项
// [] - 精确匹配,区分大小写
// [loCaseInsensitive] - 不区分大小写
// [loPartialKey] - 部分匹配
// [loPartialKey, loCaseInsensitive] - 组合使用var
Options: TLocateOptions;begin
Options := [loPartialKey]; // 部分匹配(适用于字符串)
// 对于整数 ID,使用精确匹配
if ADOQuery1.Locate('ID', ID, []) then
begin
ShowMessage('精确匹配成功');
end;end;
2. 支持多字段查找
pascal
procedure TForm1.LocateByMultipleFields(const ID: Integer; const Name: string);begin
// 多字段查找
if ADOQuery1.Locate('ID;Name', VarArrayOf([ID, Name]), []) then
begin
ShowMessage('找到匹配的记录');
end;end;
3. 定位后滚动到可视区域
pascal
procedure TForm1.LocateAndScrollToVisible(const ID: Integer);var
CurrentRow, TargetRow: Integer;begin
if ADOQuery1.Locate('ID', ID, []) then
begin
// 获取当前记录在 DBGrid 中的行位置
TargetRow := ADOQuery1.RecNo;
CurrentRow := DBGrid1.TopRow;
// 如果目标行不在可视区域,调整滚动
if (TargetRow < CurrentRow) or
(TargetRow > CurrentRow + (DBGrid1.Height div DBGrid1.DefaultRowHeight) - 1) then
begin
DBGrid1.TopRow := TargetRow;
end;
// 确保 DBGrid 获得焦点并高亮选中行
DBGrid1.SetFocus;
end;end;
4. 使用计时器延迟定位(解决窗体未显示问题)
pascal
procedure TForm1.DelayedLocate(const ID: Integer);begin
// 使用 Timer 延迟执行,确保窗体已完全加载
Timer1.Interval := 100;
Timer1.Tag := ID; // 传递 ID
Timer1.Enabled := True;end;procedure TForm1.Timer1Timer(Sender: TObject);begin
Timer1.Enabled := False;
LocateByLocate(Timer1.Tag);end;
📊 方法对比
方法优点缺点适用场景
Locate 简单快速,无需索引 大数据量时较慢 中小数据量,通用场景
FindKey 速度快,有索引支持 需要预先设置索引 大数据量,频繁查找
Filter 可临时筛选数据 会影响显示结果 需要临时过滤数据
Goto 精确控制,可添加逻辑 需要遍历,效率低 小数据量,特殊逻辑
⚠️ 注意事项
字段名:确保 'ID' 字段名与数据库实际字段名一致
数据类型:Locate 第二个参数的类型必须与字段类型匹配
数据集状态:定位前确保数据集已激活且不为空
性能优化:频繁定位时使用 DisableControls/EnableControls
书签管理:使用书签后必须释放,避免内存泄漏
pascal
// 性能优化示例ADOQuery1.DisableControls; // 暂时禁用数据感知控件更新try
// 执行多次定位操作
for i := 1 to 100 do
ADOQuery1.Locate('ID', i, []);finally
ADOQuery1.EnableControls; // 恢复更新end;
🎯 推荐方案
对于大多数应用场景,使用方法1(Locate) 是最简单、最可靠的方案。如果需要处理大数据量(10万+记录),建议使用方法2(FindKey)并建立适当的索引。
Copyright © 2014 DelphiW.com 开发 源码 文档 技巧 All Rights Reserved
晋ICP备14006235号-8 晋公网安备 14108102000087号
执行时间: 0.041439056396484 seconds