【问题标题】:Why is FMX TScrollBar OnMouseUp not working?为什么 FMX TScrollBar OnMouseUp 不起作用?
【发布时间】:2021-10-01 14:13:59
【问题描述】:

我有一个 ScrollBar,鼠标事件分配给 onChange、onMouseWheel 和 onMouseUp。 onChange 和 wheel 事件工作正常,但 onMouseUp 事件不会触发。在调试时深入到 TControl 方法,我注意到事件变量 (FOnMouseUp) 为零。该事件是在 IDE 中分配的,我将它放在表单的 onCreate 事件中,另外我尝试在创建表单后在其他各个地方分配它,但无济于事。什么给了?


这是一个简单的可重现示例,其中所有三个滚动条鼠标事件都不会触发:

 `TForm4 = class(TForm)
    ScrollBar1: TScrollBar;
    Label1: TLabel;
    procedure ScrollBar1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Single);
    procedure ScrollBar1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Single);
    procedure ScrollBar1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Single);
    procedure ScrollBar1Change(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form4: TForm4;

implementation

{$R *.fmx}

procedure TForm4.ScrollBar1Change(Sender: TObject);
begin
  Label1.Text := 'onChange: ' + Screen.MousePos.Y.ToString;
end;

procedure TForm4.ScrollBar1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  Label1.Text := 'mousedown: ' + Y.ToString;
end;

procedure TForm4.ScrollBar1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Single);
begin
  Label1.Text := 'mousemove: ' + Y.ToString;
end;

procedure TForm4.ScrollBar1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  Label1.Text := 'mouseUP: ' + Y.ToString;
end;

end.`

还有.FMX:

`object Form4: TForm4
  Left = 0
  Top = 0
  Caption = 'Form4'
  ClientHeight = 480
  ClientWidth = 640
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  DesignerMasterStyle = 0
  object ScrollBar1: TScrollBar
    SmallChange = 0.000000000000000000
    Orientation = Vertical
    Position.X = 616.000000000000000000
    Position.Y = 8.000000000000000000
    Size.Width = 18.000000000000000000
    Size.Height = 449.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 0
    OnChange = ScrollBar1Change
    OnMouseDown = ScrollBar1MouseDown
    OnMouseMove = ScrollBar1MouseMove
    OnMouseUp = ScrollBar1MouseUp
  end
  object Label1: TLabel
    Position.X = 568.000000000000000000
    Position.Y = 152.000000000000000000
    Text = 'Label1'
    TabOrder = 1
  end
end`

【问题讨论】:

  • 我们如何重现您的测试设置?详情请显示.fmx内容。
  • 您没有提供证明问题的minimal reproducible example。当我们看不到代码时,我们应该如何告诉您代码有什么问题?您需要提供一个minimal reproducible example,以便我们重现它。如果您花一些时间在tour 和阅读help center 页面以了解该网站的工作原理,然后再开始发布,您会发现您在这里的体验会好很多。
  • 感谢你们俩 - 我是新来的,感谢您的帮助。
  • 好的,我试过这个:一个垂直滚动条和一个标签的新项目。即使在这里,滚动条的鼠标事件也没有触发!

标签: delphi firemonkey mouseup onmouseup


【解决方案1】:

原因是滚动条包含子对象,例如轨道、拇指和最小和最大按钮。响应鼠标事件的是这些对象,而不是父对象。所以解决方案是将鼠标事件设置为这些对象。问题是这些对象受到保护,因此您必须创建一个新的滚动条类来设置这些事件。 TScrollBar 构造函数中尚不存在子对象,因此我发现分配它们的最佳位置是在第一个绘制事件上。

几周前我问了几乎完全相同的问题。在这里查看我自己的答案。

FMX: TScrollBar MouseDown and MouseUp events not triggering

这是您的示例,现在可以使用。我还用 4 个标签替换了您的一个标签,以便更轻松地查看调用了哪些事件。

响应鼠标事件的新滚动条类:

unit ScrollBarMouse;

interface

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

type

  // A scroll bar that responds to mouse events
  TScrollBarMouse = class(TScrollBar)
  private
    FMouseEventsSet : Boolean;
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
  end;


implementation

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

  FMouseEventsSet := False;
end;

procedure TScrollBarMouse.Paint;
begin
  inherited;

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

end.

表格单位:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls, ScrollBarMouse;

type

TForm4 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    procedure ScrollBar1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Single);
    procedure ScrollBar1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Single);
    procedure ScrollBar1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Single);
    procedure ScrollBar1Change(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    ScrollBar1 : TScrollBarMouse;
  end;

var
  Form4: TForm4;

implementation

{$R *.fmx}

procedure TForm4.FormCreate(Sender: TObject);
begin
  // Create the scroll bar object
  ScrollBar1 := TScrollBarMouse.Create(Self);
  with ScrollBar1 do begin
    Parent := Self;
    Orientation := TOrientation.Vertical;
    Position.X := 616;
    Position.Y := 8;
    Size.Width := 18;
    Size.Height := 449;
    OnMouseDown := ScrollBar1MouseDown;
    OnMouseUp := ScrollBar1MouseUp;
    OnMouseMove := ScrollBar1MouseMove;
    OnChange := ScrollBar1Change;
  end;
end;

procedure TForm4.ScrollBar1Change(Sender: TObject);
begin
  Label1.Text := 'onChange: ' + IntToStr(Round(Screen.MousePos.Y));
end;

procedure TForm4.ScrollBar1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  Label2.Text := 'mousedown: ' + IntToStr(Round(Y));
end;

procedure TForm4.ScrollBar1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Single);
begin
  Label3.Text := 'mousemove: ' + IntToStr(Round(Y));
end;

procedure TForm4.ScrollBar1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  Label4.Text := 'mouseUP: ' + IntToStr(Round(Y));
end;

end.

表单(滚动条是在运行时创建的,因此被移除):

object Form4: TForm4
  Left = 0
  Top = 0
  Caption = 'Form4'
  ClientHeight = 480
  ClientWidth = 640
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  OnCreate = FormCreate
  DesignerMasterStyle = 0
  object Label1: TLabel
    Position.X = 424.000000000000000000
    Position.Y = 144.000000000000000000
    Size.Width = 121.000000000000000000
    Size.Height = 17.000000000000000000
    Size.PlatformDefault = False
    Text = 'Label1'
    TabOrder = 3
  end
  object Label2: TLabel
    Position.X = 424.000000000000000000
    Position.Y = 168.000000000000000000
    Size.Width = 121.000000000000000000
    Size.Height = 17.000000000000000000
    Size.PlatformDefault = False
    Text = 'Label1'
    TabOrder = 2
  end
  object Label3: TLabel
    Position.X = 424.000000000000000000
    Position.Y = 192.000000000000000000
    Size.Width = 121.000000000000000000
    Size.Height = 17.000000000000000000
    Size.PlatformDefault = False
    Text = 'Label1'
    TabOrder = 1
  end
  object Label4: TLabel
    Position.X = 424.000000000000000000
    Position.Y = 216.000000000000000000
    Size.Width = 121.000000000000000000
    Size.Height = 17.000000000000000000
    Size.PlatformDefault = False
    Text = 'Label1'
    TabOrder = 0
  end
end

这是使用 Delphi 10.4 构建并在 Windows 10 中运行。

【讨论】:

  • 这正是医生吩咐的!谢谢。我不明白为什么事件分配必须在paint方法中完成,我认为这意味着它们不断被重新分配。你不能在构造函数中或者在创建控件之后执行它吗?
  • 子对象尚未在构造函数中分配,因此无法在那里完成。它只会在paint方法中第一次这样做,因为它设置了FMouseEventsSet标志。
  • 感谢您的回答。请注意,我只是稍微简化了代码。我意识到在新类中不需要单独的鼠标事件。
  • 哦,新版本更棒了!我确实必须更改自定义滚动条的绘制事件中的代码,消除 if 语句中的所有分配条件。由于未满足 if 要求,因此从未进行过实际的鼠标事件分配。所以我只使用了if not FMouseEventsSet then begin。我不明白您为什么以您使用的形式编写更复杂的 if 语句!无论如何,再次感谢,这真的成功了。
  • if 语句的条件是在尝试将鼠标事件分配给对象之前确保对象存在。我不确定他们为什么会为你失败。它对我有用。可能是因为您没有设置所有 3 个鼠标事件。检查这些可能会被删除,但我会留下对子对象的检查。
猜你喜欢
  • 2022-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-07
  • 2019-08-06
  • 2016-07-05
相关资源
最近更新 更多