Odd behavior on mouse move event on track

I am trying to implement a feature similar to most media players, where by moving the mouse over the media duration track bar, a small popup will be displayed informing you of the time your mouse is currently higher. I noticed strange behavior though when implementing the code below.

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;

      

If I clicked in the middle of the track strip, I get a value very close to the actual track value at that point, so for example, the track range is 0 to 2000 and I click somewhere in the middle, I get 1000 , but moving left or right, I start to get lower and higher values ​​respectively. So if my mouse is close to the start, for example, I can get 180 instead of 100 , which should be the actual value at that point. Can anyone point out what I am doing wrong here?

EDIT

By the actual value of the track line, I mean the value obtained from:

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

end;

      

So, I will move the mouse, say, at position 308 (here is the track from 0 to 609) and I get a perch value of 0.50574, which tells me that the track value under the mouse is at position 308 - 10114, but by clicking the mouse and activating function onChange, I get the value 10116. This difference increases as we move further from the middle of the track to either side of it.

EDIT 2

A clearer example would be this. As you can see in the image below, I move the mouse to position X = 572. This position, if expressed as a percentage for the entire track, will be 572/609 = 0.9392. Thus, one would expect the percentage of the track value at that position (min: 0 - max: 200 as shown in the figure) to be the same. In other words, MValue / max = 0.9392.

enter image description here

But after clicking on the track bar at that exact position and then asking for its value, it will not return what I calculated as "MValue" as shown in the image below (the mouse is not visible, but this image is valid after I clicked the bar track in the same position as the ActualValue update has been updated)

enter image description here

+3


source to share


2 answers


Problem 1

Your value calculation does not match the control you are using. The control does this with this code, which can be found in 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;

      

The difference is that the code here respects the thumb size. A formula is equivalent to calling this function and passing a value 0

for ThumbSize

.

If you want to replicate the behavior of a control, you will need to use this algorithm as well. You will need a secure hack to crack the class.



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;

      

Problem 2

OnMouseMove

does not fire when the cursor is over a track. This appears to be the main limitation of FMX control TTrackBar

. The main framework obviously knows that the cursor is over the thumb because it draws it in a different color, the so-called hot-watch effect. However, the structure seems to do this at the expense of giving you information that the mouse is moving.

The thumb on the track bar is implemented as a separate object. It is an object of type TThumb

. The control TTrackBar

exposes the object through a protected property. You can use a secure hack to grab the thumb object and then set its event handler OnMouseMove

. Not much fun, but certainly one way to get around this problem.

+3


source


For your initial problem, you need to dig into the style to find the exact amount of left and right padding around the track. Please note that this will vary by platform, style, and Delphi version.

You can use your own style so you know that everything will be permanent.



To solve the problem raised by David Heffernan, you can transparently control the TTrackBar (make it a click-aligned child of the tracks panel), intercept the mouse events, do your own handling, and pipe them to the tracks panel.

0


source







All Articles