You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现TDBGrid平滑滚动:按页滚动而非逐行滚动的方法

TDBGrid 按页平滑滚动实现(支持鼠标滚轮)

核心思路

TDBGrid的导航逻辑完全依赖绑定的数据集,要实现按页滚动而非逐行滚动,核心是控制数据集游标一次移动单页可见行数,同时拦截网格的垂直滚动条事件与鼠标滚轮事件,替换为自定义的分页导航逻辑。

实现步骤

1. 计算单页可见行数

先获取网格当前能显示的数据行数(排除表头高度),这个数值就是每次滚动需要移动的游标步数:

function GetGridVisibleRowCount(Grid: TDBGrid): Integer;
var
  RowHeight: Integer;
begin
  RowHeight := Grid.DefaultRowHeight;
  if RowHeight = 0 then RowHeight := Grid.Font.Height + 4; // 兜底默认行高
  Result := (Grid.ClientHeight - Grid.TitleBand.Height) div RowHeight;
end;

2. 拦截垂直滚动条事件

通过继承TDBGrid重写WndProc,处理WM_VSCROLL消息,替换默认的逐行滚动逻辑:

type
  TDBGridEx = class(TDBGrid)
  private
    procedure WMVScroll(var Msg: TWMVScroll); message WM_VSCROLL;
    procedure WMMouseWheel(var Msg: TWMMouseWheel); message WM_MOUSEWHEEL;
  end;

procedure TDBGridEx.WMVScroll(var Msg: TWMVScroll);
var
  VisibleRows: Integer;
  DataSet: TDataSet;
begin
  if not Assigned(DataSource) or not Assigned(DataSource.DataSet) then Exit;
  DataSet := DataSource.DataSet;
  VisibleRows := GetGridVisibleRowCount(Self);

  case Msg.ScrollCode of
    SB_PAGEDOWN:
      begin
        if not DataSet.Eof then
        begin
          DataSet.MoveBy(VisibleRows);
          if DataSet.Eof then DataSet.Last;
        end;
        Msg.Result := 0;
        Exit;
      end;
    SB_PAGEUP:
      begin
        if not DataSet.Bof then
        begin
          DataSet.MoveBy(-VisibleRows);
          if DataSet.Bof then DataSet.First;
        end;
        Msg.Result := 0;
        Exit;
      end;
  end;
  // 保留SB_LINEUP/SB_LINEDOWN等逐行滚动的默认逻辑,按需可修改
  inherited;
end;

3. 处理鼠标滚轮事件

在自定义网格类中添加WM_MOUSEWHEEL消息处理,将滚轮滚动转换为分页操作:

procedure TDBGridEx.WMMouseWheel(var Msg: TWMMouseWheel);
var
  VisibleRows: Integer;
  DataSet: TDataSet;
begin
  if not Assigned(DataSource) or not Assigned(DataSource.DataSet) then
  begin
    inherited;
    Exit;
  end;

  DataSet := DataSource.DataSet;
  VisibleRows := GetGridVisibleRowCount(Self);

  if Msg.WheelDelta > 0 then // 滚轮向上,翻上一页
  begin
    if not DataSet.Bof then
    begin
      DataSet.MoveBy(-VisibleRows);
      if DataSet.Bof then DataSet.First;
    end;
  end
  else // 滚轮向下,翻下一页
  begin
    if not DataSet.Eof then
    begin
      DataSet.MoveBy(VisibleRows);
      if DataSet.Eof then DataSet.Last;
    end;
  end;

  Msg.Result := 1; // 标记消息已处理,避免传递给默认逻辑
end;

4. 视觉平滑优化

在数据集游标移动后调用网格刷新方法,确保界面同步更新:

// 在DataSet.MoveBy操作后添加
Self.Update;

注意事项

  • 确保绑定的数据集支持MoveBy方法(TTable、TQuery等标准数据集均支持)
  • 若网格包含固定页脚,计算可见行数时需额外减去页脚高度
  • 测试边界场景:滚动至首尾页时,强制将游标定位到First或Last,避免数据集抛出异常

内容的提问来源于stack exchange,提问作者snowdev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 10:12:35