实现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
相关产品推荐
相关产品推荐

