FMX:TScrollBar MouseDown 和 MouseUp 事件未触发

FMX: TScrollBar MouseDown and MouseUp events not triggering

我创建了以下 class 来尝试改进滚动条的响应。原因是,如果滚动条的 onchange 事件中的代码稍微慢一点,那么更新不会生效,直到您停止拖动拇指。例如,如果在 onchange 事件中重绘 canvas,这很烦人。但是,在 TTimer 事件中更新 canvas 是顺利的。我的猜测是,这与同步的 TScrollBar OnChange 事件有关,而 TTimer 事件是异步的。我的代码尝试通过使用 TTimer 触发事件来解决 TScrollBar 问题,TTimer 使用 MouseDown 事件启用,使用 MouseUp 事件禁用。

问题是 OnMouseDown 事件根本没有触发。我还尝试在设计时向表单添加一个 TScrollBar 组件,然后检查它的 MouseDown 或 MouseUp 事件是否被触发,但它们都没有。我设法从 2013 年找到了一个类似的问题,但从未回答过。

https://codeverge.com/embarcadero.delphi.firemonkey/help-how-to-trap-mouse-down-mou/1057945

那么这些事件没有被触发是有原因的吗?我怎样才能让它们触发?

此外,如果有其他方法可以改善标准 TScrollBar 的响应,请告诉我?我正在使用 Delphi 10.4.

unit ScrollBarSmoothUnit;

interface

uses
  System.Classes, System.UITypes, FMX.StdCtrls, FMX.Types;

type

  TScrollBarSmooth = class(TScrollBar)
  private
    FTimer : TTimer;
    FLastValue : Single;

    procedure ScrollMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Single);
    procedure ScrollMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Single);
    procedure DoChange(Sender: TObject);
  public
    OnChangeSmooth : TNotifyEvent;

    constructor Create(AOwner: TComponent); override;
  end;


implementation

constructor TScrollBarSmooth.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  AutoCapture := True;
  HitTest := True;
  OnMouseDown := ScrollMouseDown;
  OnMouseUp   := ScrollMouseUp;

  FTimer := TTimer.Create(Self);
  FTimer.Interval := 40;
  FTimer.Enabled := False;
  FTimer.OnTimer := DoChange;

  FLastValue := -1;
end;

procedure TScrollBarSmooth.ScrollMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  FTimer.Enabled := True;
end;

procedure TScrollBarSmooth.ScrollMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  FTimer.Enabled := False;

  DoChange(Self);
end;

procedure TScrollBarSmooth.DoChange(Sender: TObject);
begin
  if Value = FLastValue then Exit; // No change
  FLastValue := Value;

  if Assigned(OnChangeSmooth) then OnChangeSmooth(Self);
end;

end.

下面的页面回答了我的问题(从日语翻译后)。

https://www.gesource.jp/weblog/?p=6206

TScrollBar 包含一个 Track 对象,该对象又包含一个 Thumb 对象。响应鼠标事件的是这些对象而不是滚动条。这些对象在 TScrollBar 构造函数中尚不存在,因此我在 Paint 过程中设置了鼠标事件。然后触发鼠标事件,这解决了我的性能问题。拖动滚动条现在可以更流畅地更新我的 canvas。

unit ScrollBarSmoothUnit;

interface

uses
  System.Classes, System.UITypes, FMX.StdCtrls, FMX.Types;

type

  // A scroll bar with smoother response if OnChange event is slow
  TScrollBarSmooth = class(TScrollBar)
  private
    FTimer : TTimer;
    FLastValue : Single;
    FMouseEventsSet : Boolean;
    FOnChangeSmooth : TNotifyEvent;

    procedure ScrollMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Single);
    procedure ScrollMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Single);
    procedure DoChange(Sender: TObject);
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;

    property OnChangeSmooth : TNotifyEvent write FOnChangeSmooth;
  end;


implementation

constructor TScrollBarSmooth.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  FTimer := TTimer.Create(Self);
  FTimer.Interval := 40;
  FTimer.Enabled := False;
  FTimer.OnTimer := DoChange;

  FLastValue := -1;
  FMouseEventsSet := False;
end;

procedure TScrollBarSmooth.Paint;
begin
  inherited;

  // Track and Buttons are not assigned in constructor, so set mouse events on first paint
  if not FMouseEventsSet and Assigned(Track.Thumb)
    and Assigned(MinButton) and Assigned(MaxButton) then begin
    Track.OnMouseDown       := ScrollMouseDown;
    Track.OnMouseUp         := ScrollMouseUp;
    Track.Thumb.OnMouseDown := ScrollMouseDown;
    Track.Thumb.OnMouseUp   := ScrollMouseUp;
    MinButton.OnMouseDown   := ScrollMouseDown;
    MinButton.OnMouseUp     := ScrollMouseUp;
    MaxButton.OnMouseDown   := ScrollMouseDown;
    MaxButton.OnMouseUp     := ScrollMouseUp;
    FMouseEventsSet := True;
  end;
end;

procedure TScrollBarSmooth.ScrollMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  FTimer.Enabled := True;
end;

procedure TScrollBarSmooth.ScrollMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  FTimer.Enabled := False;

  DoChange(Self);
end;

procedure TScrollBarSmooth.DoChange(Sender: TObject);
begin
  if Value = FLastValue then Exit; // No change
  FLastValue := Value;

  if Assigned(FOnChangeSmooth) then FOnChangeSmooth(Self);
end;

end.