轨迹栏鼠标移动事件的奇怪行为

时间:2014-10-28 14:53:16

标签: delphi firemonkey

我正在尝试实现类似于大多数媒体播放器的功能,通过将鼠标移动到媒体持续时间轨道栏上方,它将显示一个小弹出窗口,通知您鼠标当前位于上方。我注意到在执行下面给出的代码时有一种奇怪的行为。

procedure TForm1.TrackBar1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Single);
var
  pers: Extended;
begin
  pers := (X/TrackBar1.Width);
  PixelLabel.Text := FloatToStr(pers * TrackBar1.Max);
end;

如果我在轨迹栏的中间单击,我会得到一个非常接近该点实际轨迹条值的值,所以如果例如轨迹栏范围从 0 变为 2000 然后我点击中间某处我 1000 ,但是当我向左或向右移动时,我开始分别得到越来越小的值。因此,如果我的鼠标接近开头,例如我可能会 180 而不是 100 ,那应该是该点的实际值。有人能指出我在这里做错了什么吗?

修改

根据实际跟踪条值,我的意思是从以下值得出的值:

procedure TForm1.TrackBar1Change(Sender: TObject);
begin
  ActualLabel.Text := 'Actual Val: '+FloatToStr(TrackBar1.Value);

end;

所以我会移动鼠标,让我们说位置308(轨道栏从0到609这里),我将得到一个 perch 值为0.50574,告诉我该值的值位于308位置的鼠标下方的轨迹栏是10114,但是通过单击鼠标并启动onChange函数,我得到的值为10116.当我们从轨道条的中间位置进一步向其中任何一个方向移动时,这种差异会增加侧上。

编辑2

更清楚的例子就是这样。如下图所示,我将鼠标移动到位置X = 572。如果以整个轨迹条的百分比表示,该位置将是572/609 = 0,9392。因此可以预期,该位置的轨迹条的值的百分比(最小值:0 - 最大值:200,如图所示)将是相同的。换句话说,MValue / max = 0,9392。

enter image description here

但是在单击该确切位置的轨迹栏然后请求其值后,它将不会返回我计算为“MValue”的内容,如下图所示(鼠标不可见但是这个图像确实是在我点击了轨道之后栏位于同一位置,如您所见,ActualValue已更新)

enter image description here

2 个答案:

答案 0 :(得分:3)

问题1

您的值计算与控件使用的值不匹配。该控件使用此代码执行此操作,该代码可在FMX.StdCtrls

中找到
function PosToValue(MinValue, MaxValue, ViewportSize, ThumbSize, TrackSize, 
  Pos: Single; IgnoreViewportSize: boolean): Single;
var ValRel: Double;
begin
  Result := MinValue;
  if (ViewportSize < 0) or IgnoreViewportSize then
    ViewportSize := 0;
  ValRel := TrackSize - ThumbSize;
  if ValRel > 0 then
  begin
    ValRel := (Pos - ThumbSize / 2) / ValRel;
    if ValRel < 0 then
      ValRel := 0;
    if ValRel > 1 then
      ValRel := 1;
    Result := MinValue + ValRel * (MaxValue - MinValue - ViewportSize);
  end;
end;

不同之处在于这里的代码允许拇指尺寸。您的公式等同于调用此函数并为0传递ThumbSize的值。

如果要复制控件的行为,则还需要使用此算法。你需要受保护的黑客才能破解课程。

type
  THackedTrackBar = class(TTrackBar);

procedure TForm1.TrackBar1MouseMove(Sender: TObject; Shift: TShiftState; 
  X, Y: Single);
var
  tb: THackedTrackBar;
begin
  tb := THackedTrackBar(TrackBar1);
  Label1.Text := FloatToStr(
    PosToValue(
      tb.Min,
      tb.Max,
      tb.ViewportSize,
      tb.GetThumbSize(tb.FIgnoreViewportSize),
      tb.Width,
      X,
      tb.FIgnoreViewportSize
    )
  );
end;

问题2

当光标位于轨道滑块上时,

OnMouseMove不会触发。这似乎是FMX TTrackBar控件的基本限制。底层框架显然意识到光标在拇指上方,因为它以不同的颜色绘制它,即所谓的热跟踪效果。但是,框架似乎这样做是为了让你知道鼠标正在移动。

轨迹栏上的滑块实现为单独的对象。它是TThumb类型的对象。 TTrackBar控件通过受保护的属性公开对象。您可以使用受保护的hack来获取拇指对象,然后设置其OnMouseMove事件处理程序。不是很有趣,但肯定是解决问题的一种方法。

答案 1 :(得分:0)

对于您的初始问题,您需要深入了解样式,以找到轨道栏周围左右填充的确切数量。请注意,这将取决于平台,样式和Delphi版本。

您可以考虑使用自己的风格,这样您就知道一切都会保持不变。

要解决David Heffernan提出的问题,您可以对TTrackBar进行透明控制(使其成为轨道栏的客户端对齐子项),拦截鼠标事件,进行自己的处理并将其传递给轨迹栏。