Reputation: 3422
I am trying to implement a feature similar to most media players where by moving your mouse above the media duration track bar it will display a small popup informing you on the time your mouse is currently above. I noticed an odd behaviour though while implementing the code given 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 click in the middle of the track bar I will get a value quite close to the actual track bar value at that point, so if for example the track bar range goes from 0 to 2000 and I click somewhere in the middle I get 1000, but as I move to the left or right I start to get smaller and bigger values respectively. So if my mouse is close to the start for example I might get 180 instead of 100 that should be the actual value at that point. Can someone point out what is it that I am doing wrong here?
EDIT
By actual track bar value what I mean is the value derived from:
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
ActualLabel.Text := 'Actual Val: '+FloatToStr(TrackBar1.Value);
end;
So I will move the mouse lets say at position 308 (the track bar goes from 0 to 609 here) and I will get a perch value of 0.50574 that is telling me that the value of the track bar under the mouse at position 308 is 10114, but by clicking the mouse and firing up the onChange function I get a value of 10116. This difference sends to increase as we go further from the middle of the track bar to either one of its sides.
EDIT 2
A clearer example would be this. As seen in the image below I move the mouse at position X=572. This position if expressed as a percentage for the whole track bar would be 572/609 = 0,9392. So one would expect that the percentage of the value of the track bar at that position (min:0 - max:200 as the image shows) would be the same. In other words, MValue/max = 0,9392.
But after clicking the track bar at that exact position and then requesting its value it won't return what I computed as 'MValue' as the image below shows (Mouse is not visible but this image is indeed after I clicked the track bar in the same position, as you can see the ActualValue was updated)
Upvotes: 3
Views: 1778
Reputation: 612854
Problem 1
Your calculation of value does not match that used by the control. The control does it 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 makes an allowance for the thumb size. You formula is equivalent to calling this function and passing a value of 0
for ThumbSize
.
If you want to replicate the behaviour of the control, then you'll need to use this algorithm also. You'll need the protected 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 the track thumb. This seems to be a basic limitation of the FMX TTrackBar
control. The underlying framework is obviously aware that the cursor is over the thumb because it paints it in a different colour, the so-called hot-tracking effect. However, the framework appears to do this to the detriment of letting you know that the mouse is moving.
The thumb on the track bar is implemented as a separate object. It's an object of type TThumb
. The TTrackBar
control exposes the object via a protected property. You can use the protected hack to get hold of the thumb object and then set its OnMouseMove
event handler. Not a whole lot of fun, but certainly one way to work around the issue.
Upvotes: 3
Reputation: 4211
For your initial problem you will need to dig into the style to find the exact amount of left and right padding around the track bar. Note though that this will vary depending on the platform, style and Delphi version.
You might consider using your own style so you know everything will be constant.
To solve the issue raised by David Heffernan you could put a transparent control over the TTrackBar (make it a client aligned child of the track bar), intercept mouse events, do your own processing and pass them down to the track bar.
Upvotes: 0