Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook (preview only)

Author Topic: Possible Bug in TTrackbar (win7-x64)?  (Read 1364 times)

wp

• Hero Member
• Posts: 6654
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #15 on: September 03, 2019, 06:59:00 pm »
ok. Undid the change in trunk, it was a bad idea.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

feds

• New Member
• Posts: 32
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #16 on: September 03, 2019, 09:59:21 pm »
This is off-topic, but I want to add a comment because I think that you are misunderstanding the meaning of the property "Frequency" here. Really, this property is named in a misleading way: in common sense, the word "frequency" implies: "High frequency -> many ticks". But it's the other way round: "High frequency --> less ticks"! The default parameters of a TrackBar have Max = 10 and Frequecy = 1 --> there are 10 intervals (or: 11 ticks). Now set the Frequeny higher to 2 - now we have LESS intervals (5, or 6 ticks). Therefore, the property should be understood as "TickIntervals"

Your calculation "tickRange / Width" is wrong because it calculates the number of intervals. You should do: "tickRange / Count" instead to determine the "Frequency" value.

Learning is never off-topic. Thanks for your effort

I understand the frequency in the meaning of frequent or repeated.  I.e. taking the default trackbar [0..10] and frequency:=5 gives me only one bar in the middle.
The trackbar makes a tick every 5 steps. Is this wrong?

But indeed, i was calculating the intervals when the widths is to small to show all ticks.

My major point was to keep the range (min/max) intact because i assume possible bugs when changing this (i.e. increasing min in a lighting controller would keep the lamps glowing).

Hence the idea was to put as much as possible of the required ticks into the available width (wich was assumed to be acceptable small).

Moreover i was not aware that there is a count anywhere around.  Hence i take (simply) the width to create the frequency. Or as you call it tick-intervall (much better name btw.)

Unfortunally it still does not do the job. Too bad

Regards
Feds

BrunoK

• Full Member
• Posts: 204
• Retired programmer
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #17 on: September 04, 2019, 04:53:52 pm »
I don't think anything can be done to correct the large memory usage.

Have found a C# problem that describes (the answer) what seems to also happen in Lazarus.
https://www.oipapio.com/question-1739276

Here after a little project  that feds could try. (Without any warranty ...)
Code: Pascal  [Select]
1. object Form1: TForm1
2.   Left = 880
3.   Height = 115
4.   Top = 173
5.   Width = 320
6.   Caption = 'Form1'
7.   ClientHeight = 115
8.   ClientWidth = 320
9.   OnShow = FormShow
10.   LCLVersion = '2.1.0.0'
11.   object TrackBar1: TTrackBar
12.     Left = 104
13.     Height = 32
14.     Top = 56
15.     Width = 208
16.     Frequency = 64000
17.     LineSize = 2
18.     Max = 100
19.     Min = -100
20.     OnChange = TrackBar1Change
21.     PageSize = 1
22.     Position = 0
23.     ScalePos = trBottom
24.     Anchors = [akTop, akLeft, akRight]
25.     OnResize = TrackBar1Resize
26.     TabOrder = 0
27.   end
28.   object LabeledEdit1: TLabeledEdit
29.     Left = 8
30.     Height = 23
31.     Top = 56
32.     Width = 80
33.     EditLabel.Height = 15
34.     EditLabel.Width = 80
35.     EditLabel.Caption = 'Volume [0..10]'
36.     EditLabel.ParentColor = False
37.     TabOrder = 1
38.     Text = 'vol.'
39.     OnChange = LabeledEdit1Change
40.   end
41. end
Code: Pascal  [Select]
1. unit frmTrackBar;
2.
3. {\$mode objfpc}{\$H+}
4.
5. // https://forum.lazarus.freepascal.org/index.php/topic,46606.0.html?PHPSESSID=70njdrempm7i7uc0r6t25vg7l5
6.
7. // Similar problem in C#
8. //  https://www.oipapio.com/question-1739276
9.
10.
11. interface
12.
13. uses
14.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, StdCtrls,
15.   ExtCtrls;
16.
17. type
18.
19.   TVolumeChanger = (vcNone, vcText, vcTrack, vcTrackResize);
20.
21.   { TForm1 }
22.
23.   TForm1 = class(TForm)
24.     LabeledEdit1: TLabeledEdit;
25.     TrackBar1: TTrackBar;
26.     procedure FormShow(Sender: TObject);
27.     procedure LabeledEdit1Change(Sender: TObject);
28.     procedure TrackBar1Change(Sender: TObject);
29.     procedure TrackBar1Resize(Sender: TObject);
30.   private
31.     procedure SetVolume(AValue: Real);
32.   private
33.     FVolume : Real;
34.     FVolumeChanger : TVolumeChanger;
35.     procedure UpdateTrackBarFreq(aTrackBar : TTrackBar; aGraduation : integer = 10);
36.     property Volume : Real read FVolume write SetVolume;
37.   public
38.
39.   end;
40.
41. var
42.   Form1: TForm1;
43.
44. implementation
45.
46. {\$R *.lfm}
47.
48. uses
49.   Windows;
50.
51. procedure TForm1.FormShow(Sender: TObject);
52. begin
53.   TrackBar1.Min := 0;
54.   TrackBar1.Max := TrackBar1.Width;
55.   TrackBar1.OnChange(TrackBar1);
56.   UpdateTrackBarFreq(TrackBar1);
57. end;
58.
59. procedure TForm1.LabeledEdit1Change(Sender: TObject);
60. var
61.   lVolume : real;
62. begin
63.   if FVolumeChanger <> vcNone then
64.     Exit;
65.   FVolumeChanger := vcText;
66.   if TryStrToFloat(LabeledEdit1.Text, lVolume) then
67.     Volume := lVolume;
68.   FVolumeChanger := vcNone;
69. end;
70.
71. procedure TForm1.TrackBar1Change(Sender: TObject);
72. begin
73.   if FVolumeChanger <> vcNone then
74.     Exit;
75.   FVolumeChanger := vcTrack;
76.   Volume := TrackBar1.Position / TrackBar1.Frequency;
77.   LabeledEdit1.Text := Format('%.2g', [Volume]);
78.   FVolumeChanger := vcNone;
79. end;
80.
81. procedure TForm1.TrackBar1Resize(Sender: TObject);
82. var
83.   lOldVolume : real;
84. begin
85.   if FVolumeChanger <> vcNone then
86.     Exit;
87.   lOldVolume := Volume;
88.   FVolumeChanger := vcTrackResize;
89.   TrackBar1.Max := TrackBar1.Width;
90.   UpdateTrackBarFreq(TrackBar1);
91.   TrackBar1.Position := Trunc(FVolume * TrackBar1.Frequency);
92.   FVolumeChanger := vcNone;
93. end;
94.
95. procedure TForm1.SetVolume(AValue: Real);
96. begin
97.   if FVolume=AValue then
98.     Exit;
99.   FVolume:=AValue;
100.   TrackBar1.Position := Trunc(FVolume * TrackBar1.Frequency);
101. end;
102.
103. procedure TForm1.UpdateTrackBarFreq(aTrackBar : TTrackBar; aGraduation : integer = 10);
104. var
105.   lFreq : integer;
106. begin
107.   lFreq := (aTrackBar.Max -  aTrackBar.Min) div (aGraduation-1);
108.   TrackBar1.max := lFreq * 10;
109.   TrackBar1.Frequency:=lFreq;
110. end;
Lazarus trunk r. 62137/27.10.2019 (+/- patches regarding TScrollBar, IntitalSetupDialog, Options.Environment options, SearchResults).  Lazarus 3.0.6 raw from svn.
FPC 3.0.4 32 bits. (+heaptrc with leaked ClassName+Revisited TList) , Windows 10 Pro x64 (v. 1903 / 18362.418)

winni

• Hero Member
• Posts: 717
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #18 on: September 04, 2019, 05:25:04 pm »
So what to do?

Restrict the windows version to the maximum for max to 10.000 and write some words about it in the doc.

Or write a totaly new owner drawn trackbar for windows.

Or any other ideas?

Btw As far as I know the value for min is not allowed to be negative due to M\$ docs.

Winni

jamie

• Hero Member
• Posts: 2261
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #19 on: September 04, 2019, 05:52:39 pm »
interesting, But I think there  must be a better way for this, like hooking the TrackBar's window procedure and control the cycling there to restrict the number of calls.

Has anyone yet investigated the Message Que for a flood? Windows provides a PeekMessage where by you can remove all messages found. This appears to be a flooding problem or maybe there is some Application.ProcessMessages in the loop of the LCL code.

Number 1 at blue screen app creations!

wp

• Hero Member
• Posts: 6654
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #20 on: September 04, 2019, 05:55:29 pm »
Here is another, less destructive workaround than before. Like the previous one it switches to "no ticks" style when the range is greater than some critical value, 100,000 this time. But now it operates in the Windows widgetset only and does not modify properties persistently.

Of course, something like Max = 200000 and Frequency = 20000 (10 intervals) still breaks existing code because the Ticks are hidden now. But that's life... If this really is a problem the user can rescale the values to bring Max below 100000.

Open Win32WSComCtrls.pp from (lazarus)\lcl\interfaces\win32 and replace the method ApplyChanges by the following code:
Code: Pascal  [Select]
1. class procedure TWin32WSTrackBar.ApplyChanges(const ATrackBar: TCustomTrackBar);
2. var
3.   wHandle: HWND;
4.   NewStyle: integer;
5. const
6.   StyleMask = TBS_AUTOTICKS or TBS_NOTICKS or TBS_VERT or TBS_TOP or TBS_BOTH or
7.     TBS_ENABLESELRANGE or TBS_REVERSED;
8.   TickStyleStyle: array[TTickStyle] of DWORD = (TBS_NOTICKS, TBS_AUTOTICKS, 0);
9.   OrientationStyle: array[TTrackBarOrientation] of DWORD = (TBS_HORZ, TBS_VERT);
10.   TickMarksStyle: array[TTickMark] of DWORD = (TBS_BOTTOM, TBS_TOP, TBS_BOTH);
11.   SelRangeStyle: array[Boolean] of DWORD = (0, TBS_ENABLESELRANGE);
12.   ReversedStyle: array[Boolean] of DWORD = (0, TBS_REVERSED);
13. begin
14.   with ATrackBar do
15.   begin
16.     { cache handle }
17.     wHandle := Handle;
18.     if Max - Min > 100000 then                                    // <---- new
19.       NewStyle := TickStyleStyle[tsNone]                          // <--- new
20.     else
21.       NewStyle := TickStyleStyle[TickStyle];                      // <--- new
22.     NewStyle := NewStyle or OrientationStyle[Orientation] or      // <--- modified
23.                 TickMarksStyle[TickMarks] or SelRangeStyle[ShowSelRange] or ReversedStyle[Reversed];
25.     Windows.SendMessage(wHandle, TBM_SETRANGEMAX, Windows.WPARAM(True), Max);
26.     Windows.SendMessage(wHandle, TBM_SETRANGEMIN, Windows.WPARAM(True), Min);
27.     if Reversed then
28.       Windows.SendMessage(wHandle, TBM_SETPOS, Windows.WPARAM(True), Max + Min - Position)
29.     else
30.       Windows.SendMessage(wHandle, TBM_SETPOS, Windows.WPARAM(True), Position);
31.     Windows.SendMessage(wHandle, TBM_SETLINESIZE, 0, LineSize);
32.     Windows.SendMessage(wHandle, TBM_SETPAGESIZE, 0, PageSize);
33.     Windows.SendMessage(wHandle, TBM_SETTICFREQ, Frequency, 0);
34.     if ((SelStart = 0) and (SelEnd = 0)) or not ShowSelRange then
35.       Windows.SendMessage(wHandle, TBM_CLEARSEL, Windows.WPARAM(True), 0)
36.     else
37.     begin
38.       Windows.SendMessage(wHandle, TBM_SETSELSTART, Windows.WParam(False), SelStart);
39.       Windows.SendMessage(wHandle, TBM_SETSELEND, Windows.WParam(True), SelEnd)
40.     end;
41.   end;
42. end;
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

jamie

• Hero Member
• Posts: 2261
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #21 on: September 04, 2019, 06:23:01 pm »
But that gives you an empty tick line?

btw, this effects the Designer too if you set the value high in it.

Wouldn't it be better to simply draw a solid line for values where there isn't enough pixels?

This would mean doing your own drawing but it's better than what we have now
Number 1 at blue screen app creations!

winni

• Hero Member
• Posts: 717
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #22 on: September 04, 2019, 07:17:34 pm »
We got a natural visible threshold  value:

The linewidth of the ticks is 1.
Between two ticks there should be a gap with the minimum of 1.
So our threshold is component.width div 2. (Ok, a little bit less)

If the number of ticks is greater than this value, divide by 2 in a loop until it fits.

That would be an easy solution.

Winni

ASerge

• Hero Member
• Posts: 1433
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #23 on: September 04, 2019, 07:33:48 pm »

wp

• Hero Member
• Posts: 6654
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #24 on: September 04, 2019, 07:52:09 pm »
We got a natural visible threshold  value:

The linewidth of the ticks is 1.
Between two ticks there should be a gap with the minimum of 1.
So our threshold is component.width div 2. (Ok, a little bit less)

If the number of ticks is greater than this value, divide by 2 in a loop until it fits.

That would be an easy solution.

Winni
What do you want to do? Alter the Frequency value? This will not work because it's Max which causes the trouble: Set Max := MaxInt and Frequency := MaxInt div 2, and the issue will still be there although there are only 3 ticks to be drawn. Alter the Max value? That's a no-go because it directly affects the visual position of the slider.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

wp

• Hero Member
• Posts: 6654
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #25 on: September 04, 2019, 07:57:23 pm »
Yes, it's like what I posted in reply #20. However I would put less emphasis on Delphi compatibility and increase the limiting value to 100,000 or even 1,000,000 because it reduces the chance of a conflict as noted by winni in reply #4.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

ASerge

• Hero Member
• Posts: 1433
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #26 on: September 04, 2019, 08:20:55 pm »
Yes, it's like what I posted in reply #20. However I would put less emphasis on Delphi compatibility and increase the limiting value to 100,000 or even 1,000,000 because it reduces the chance of a conflict as noted by winni in reply #4.
The number 10000 was chosen as the maximum resolution in pixels. To draw tics often than pixel pointless.

jamie

• Hero Member
• Posts: 2261
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #27 on: September 04, 2019, 08:29:55 pm »
I think it is more logical to restrain the Frequency to the width of the control?

so if the range value exceeds the control's width in pixels it should automatically adjust the frequency for a proper fit.

I just ran some test here and it does not effect any code that I can see, it actually works perfectly because I still get my graph bar even with high values.

So basically this..

If TrackBar.Width < Range / Frequency Then Frequency := Range / TrackBar.Width;

To me that is a better choice because at least you still get a tick bar and it does not flood the message que with notifications when updating the ticks

Can you please put in a Option in the properties to select which way to adjust the conditions  for
large values?

Number 1 at blue screen app creations!

wp

• Hero Member
• Posts: 6654
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #28 on: September 04, 2019, 08:36:55 pm »
In the code of reply #4
Code: Pascal  [Select]
1. trackbar.Min        := 0;
2. trackbar.Max        := 50000;
3. trackbar.Frequency  := 5000;
we have 10 intervals (= 50000/5000) - this means: 11 ticks. And this is what is displayed by the LCL Trackbar. But with your patch there are no more ticks because Max is > 10000.

Suppose the trackbar represents the number of iterations in some software calculation. Ideally the user does not think about readjustment these numbers to the usable range below 10000 in your patch. The longer he can use direct numbers the better. Therefore I'd increase the limit value beyond which ticks are turned off.

On the other hand, the trackbar ticks are rather useless because they are not labeled. So maybe, my comment added just too much noise...
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

jamie

• Hero Member
• Posts: 2261
Re: Possible Bug in TTrackbar (win7-x64)?
« Reply #29 on: September 04, 2019, 08:44:48 pm »
A Proper patch would be to simply calculate the Frequency to limit the drawing ticks automatically.

I do have one app that uses that control for a file pointer and it does get big at times but I would really love to not loose the bar looks even though it's useless there because I have other graphics around it.

P.S.
I have had slowness in some apps using this control before and never investigated the cause, now I think that is it.
Number 1 at blue screen app creations!