delphi 根据 ID 定位选中 DBGrid 记录  
官方Delphi 学习QQ群: 682628230(三千人)\n
频道

delphi 根据 ID 定位选中 DBGrid 记录


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