FMX TScrollBar的MouseDown、MouseUp事件不触发如何解决及滚动响应优化
问题原因
- FireMonkey框架下的
TScrollBar为复合控件,内部包含滑块、上下/左右按钮、滚动轨道三个子控件。所有鼠标交互事件默认被子控件捕获处理,不会向上冒泡到TScrollBar父组件本身,因此直接绑定父组件的OnMouseDown、OnMouseUp事件不会触发。
解决方案
方案1:使用自带OnScroll事件实现(推荐)
TScrollBar原生的OnScroll事件自带拖动状态标识,完全可以替代鼠标事件实现你的逻辑,无需处理子控件事件,修改后的完整代码如下:
unit ScrollBarSmoothUnit; interface uses System.Classes, System.UITypes, FMX.StdCtrls, FMX.Types; type TScrollBarSmooth = class(TScrollBar) private FTimer : TTimer; FLastValue : Single; procedure DoScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Single); procedure DoChange(Sender: TObject); public OnChangeSmooth : TNotifyEvent; constructor Create(AOwner: TComponent); override; end; implementation constructor TScrollBarSmooth.Create(AOwner: TComponent); begin inherited Create(AOwner); OnScroll := DoScroll; FTimer := TTimer.Create(Self); FTimer.Interval := 40; FTimer.Enabled := False; FTimer.OnTimer := DoChange; FLastValue := -1; end; procedure TScrollBarSmooth.DoScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Single); begin case ScrollCode of scBeginDrag: FTimer.Enabled := True; scEndDrag: begin FTimer.Enabled := False; DoChange(Self); end; end; end; procedure TScrollBarSmooth.DoChange(Sender: TObject); begin if Value = FLastValue then Exit; FLastValue := Value; if Assigned(OnChangeSmooth) then OnChangeSmooth(Self); end; end.
方案2:给子控件绑定鼠标事件
如果确实需要监听鼠标事件,可以在控件创建时遍历所有子控件,统一绑定事件,修改构造函数即可:
constructor TScrollBarSmooth.Create(AOwner: TComponent); var i: Integer; begin inherited Create(AOwner); AutoCapture := True; HitTest := True; // 给自身和所有子控件绑定鼠标事件 OnMouseDown := ScrollMouseDown; OnMouseUp := ScrollMouseUp; for i := 0 to ControlsCount - 1 do begin Controls[i].HitTest := True; Controls[i].OnMouseDown := ScrollMouseDown; Controls[i].OnMouseUp := ScrollMouseUp; end; // 原计时器逻辑保持不变 FTimer := TTimer.Create(Self); FTimer.Interval := 40; FTimer.Enabled := False; FTimer.OnTimer := DoChange; FLastValue := -1; end;
其他优化滚动条响应的方案
- 耗时的重绘逻辑拆分到后台线程执行,仅将渲染完成的位图抛到主线程更新,避免阻塞主线程消息循环
- 拖动过程中可先绘制低精度的预览内容,拖动停止后再绘制完整的高精度内容,进一步降低拖动时的性能消耗
- 调整计时器间隔匹配屏幕刷新率,普通60Hz屏幕对应16ms间隔,可平衡流畅度和资源占用
内容的提问来源于stack exchange,提问作者XylemFlow
相关产品推荐
相关产品推荐

