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

VCL TStringGrid触摸平移问题:惯性未结束时无法响应二次操作

问题描述

我有一个包含数百行数据的TStringGrid,需要在触摸屏设备上支持触摸平移(手指上下滑动)浏览数据。已设置以下属性:

Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRowMoving, goEditing, goRowSelect, goThumbTracking, goFixedRowClick, goFixedHotTrack, goFixedRowDefAlign]
TabOrder = 0
Touch.InteractiveGestures = [igPan]
Touch.InteractiveGestureOptions = [igoPanSingleFingerVertical, igoPanInertia]
Touch.ParentTabletOptions = False
Touch.TabletOptions = []

未使用GestureManager。当前触摸拖动和点击操作正常,但平移存在问题:

  • 初始操作正常,网格滚动带惯性;等待惯性超时后二次操作也正常。
  • 若在惯性计时器超时前发起二次操作,网格会停止滚动,需等计时器结束才会再次响应。

现有OnGesture事件代码:

procedure TForm2.GrdVehiclesGesture(Sender: TObject; const EventInfo: TGestureEventInfo; var Handled: Boolean);
var
  InertiaActiveChanged: Boolean;
begin
  if EventInfo.GestureID = igiPan then
  begin
    InertiaActiveChanged := False;

    if not FInertiaActive and (gfBegin in EventInfo.Flags) then
    begin
      FInertiaActive := True;
      SendDebug('Inertia starting');
      InertiaActiveChanged := True;
    end;

    if FInertiaActive and (gfEnd in EventInfo.Flags) then
    begin
      FInertiaActive := False;
      SendDebug('Inertia stopping');
      InertiaActiveChanged := True;
    end;

    if not FInertiaActive and not InertiaActiveChanged then
    begin
      SendDebug('Panning outside inertia');
      Handled := True;
    end;
  end
  else
    SendDebug(IntToStr(EventInfo.GestureID) + ' ' + IntToStr(EventInfo.Location.Y));
end;

调试信息显示:平移时输出Inertia starting,数秒后输出Inertia stopping;若在停止前发起二次操作,会输出Panning outside inertia且网格不滚动。

需要实现:无论惯性计时器是否激活,网格都能响应平移操作。

解决方案

问题出在原OnGesture事件的逻辑里——当惯性激活(FInertiaActive=True)时,新的平移手势没有被标记为Handled:=True,导致网格忽略操作;同时没有主动终止当前惯性,让新触摸无法接管。

修改后的代码如下:

procedure TForm2.GrdVehiclesGesture(Sender: TObject; const EventInfo: TGestureEventInfo; var Handled: Boolean);
begin
  if EventInfo.GestureID = igiPan then
  begin
    // 检测到新平移开始,终止当前惯性(如果存在)
    if gfBegin in EventInfo.Flags then
    begin
      if FInertiaActive then
      begin
        SendDebug('Interrupting inertia for new pan');
        // 发送消息强制终止惯性滚动
        SendMessage(TStringGrid(Sender).Handle, WM_VSCROLL, SB_ENDSCROLL, 0);
      end;
      FInertiaActive := True;
      SendDebug('Inertia starting');
    end
    // 平移结束,标记惯性停止
    else if gfEnd in EventInfo.Flags then
    begin
      FInertiaActive := False;
      SendDebug('Inertia stopping');
    end;

    // 所有平移手势都标记为已处理,确保网格响应
    Handled := True;
  end
  else
    SendDebug(IntToStr(EventInfo.GestureID) + ' ' + IntToStr(EventInfo.Location.Y));
end;

关键修改说明

  1. 主动终止惯性:当检测到新的gfBegin手势时,通过SendMessage发送WM_VSCROLL+SB_ENDSCROLL,强制停止当前惯性滚动,让新触摸操作直接接管。
  2. 统一标记Handled:移除原代码中仅在非惯性阶段标记Handled:=True的逻辑,所有平移手势都标记为已处理,确保网格响应每一次触摸操作。
  3. 简化状态判断:把FInertiaActive的状态更新逻辑简化,直接根据gfBegin和gfEnd标志处理,避免复杂判断带来的逻辑漏洞。

修改后,无论当前是否处于惯性滚动阶段,用户的二次触摸平移都会立即生效,不会出现等待计时器结束的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 13:33:19