Recent

Author Topic: [SOLVED] TSpinEditEx and TFloatSpinEditEx changes value when resizing Form  (Read 386 times)

dangersgromit

  • New member
  • *
  • Posts: 8
Hello,

I've got a problem that puzzles me since updating to Lazarus 3.02 and is still there in 4.0RC2, (both X64 Windows only). I tried several times to reproduce it in a simpler project to upload the sources. But every time I make a sample project the error never occurs. So I even removed all the code from the original project and recoded all the filter-pages. The error remains once it is fully coded.

Since the program is highly integrated with our company's data structure I cannot show the original source code.

This is what happens:
When I start the programme it loads a lot of forms into an TExtendedNotebook (much like TDINotebook does). One of the forms contains a transaction viewer for customer receipts and internal cashier related transactions.
The user can set filters for a lot of data and search for transactions matching these criterias. There a about 100 Filter options. Some of these filter's are TSpinEditEx or TFloatSpinEditEx with each an MinValue, MaxValue, NullValue and TextHint set.

You get an "emtpy" Form like this, when opening the Transaction Viewer:
see: TAV-BEFORE.jpg

Now you just resize the Notebook / PageControl / TDI (using the TSplitter in the middle or the mouse on the frame on the right or left side).
Every TSpinEditEx /TSpinEditFloat changes it value.
See: TAV-AFTER-RESIZE.jpg

I have no idea what triggers it.
I even turn on spineditdebug an included the Logfile - maybe someone can see what happens.

If I patch the TSpinEditExBase.RealGetText Method to this the values to not change on "form/page/parent" resize anymore. But the Up/Down Control wont function either.

Code: Pascal  [Select][+][-]
  1. function TSpinEditExBase.RealGetText: TCaption;
  2. begin
  3.   Result := ValueToStr(FValue);
  4. end;    
  5.  

Any ideas why that happens and how I can fix this behaviour?

FYI: I have a second tools which only contains the transaction viewer with a few other options some employees are not allowed to use. It uses exactly the same code (most of it is include files). Only the Form and lfm have been modified to work "standalone" or a "page within a TExtendedNotebook".

Once again: If I can could reproduce this with a sample project, I would upload that. But in any sample project I came up so far the error does not occur.

Best Regards
Klaus
« Last Edit: March 14, 2025, 08:29:29 am by dangersgromit »

Zvoni

  • Hero Member
  • *****
  • Posts: 2961
Re: TSpinEditEx and TFloatSpinEditEx changes value when resizing Form
« Reply #1 on: March 13, 2025, 02:09:06 pm »
Once again: If I can could reproduce this with a sample project, I would upload that. But in any sample project I came up so far the error does not occur.

Best Regards
Klaus
Conclusion: You have in a Resize/Repaint (whatever) Event of your Form/NoteBook (Whatever) Code that sets the value and/or triggers the Up/Down Code of those SpinEdits
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

dangersgromit

  • New member
  • *
  • Posts: 8
Re: TSpinEditEx and TFloatSpinEditEx changes value when resizing Form
« Reply #2 on: March 13, 2025, 05:17:18 pm »
Hi Zvoni,

I think I don't have any events triggering the up/down. In this project I do not override any paint methods or use an OnPaint event.

The main form just calculates the width of the first panel in the Statusbar.
Code: Pascal  [Select][+][-]
  1. procedure TfrmDNInfo.FormResize(Sender: TObject);
  2. var
  3.   i,l : Integer;
  4. begin
  5.   With MainStatusbar do
  6.   begin
  7.     Panels[1].Width:= 100;
  8.     Panels[2].Width:= 100;
  9.     Panels[3].Width:= 220;
  10.     Panels[4].Width:= 220;
  11.     Panels[5].Width:= 200;
  12.     Panels[6].Width:= 20;
  13.  
  14.     l := 0;
  15.     For i := 1 to 6 do
  16.       l := l + Panels[i].Width;
  17.  
  18.     Panels[0].Width:= frmDNInfo.Width - l;
  19.  
  20.   end;
  21. end;
  22.  

The ExtendedNotebook (called ModuleHost) does not have an OnResize event set, nor does it override any resize method.
The only event triggered is setting the Modulename and the modules icon on the mainform for optical reasons
Code: Pascal  [Select][+][-]
  1. procedure TfrmDNInfo.ModuleHostChange(Sender: TObject);
  2. var
  3.   i : Integer;
  4. begin
  5.   if (ActiveModule) = NIL then Exit;
  6.   SelectedForm.Caption := ActiveModule.Caption;
  7.   HeaderImage.ImageIndex := ActiveModule.ImageIndex;
  8.  
  9.   szLastUpdLocal := TModuleForm(ModuleHost.ActiveForm).szLastUpdLocal;
  10.  
  11.   AutoCloseTimerStopTimer(Sender);
  12. end;  
  13.  

The TAViewer form is an modified TForm I call TModuleForm which overrides the DoOnResize procedure. It modifies the Statusbar, if the form is floating, but not anything for other controls in any of the forms of this class.
An additional OnResize-Event is not used by this form.
Code: Pascal  [Select][+][-]
  1. procedure TModuleForm.DoOnResize;
  2. var
  3.   i : Integer;
  4.   w : Integer;
  5. begin
  6.   inherited DoOnResize;
  7.  
  8.   if (not Floating) and (ModuleHost <> NIL) then
  9.   begin
  10.     i := ModuleHost.FindFormPage(Self);
  11.     ModuleHost.Pages[i].ImageIndex:= ImageIndex;
  12.     if PrefPageIndex <> ModuleHost.Pages[i].PageIndex then
  13.       ModuleHost.Pages[i].PageIndex := PrefPageIndex;
  14.   end;
  15.  
  16.   if (not Assigned(fStatusbar)) or (fStatusbar = NIL) then Exit;
  17.  
  18.   While LocalStatusbar.Panels.Count < fStatusbar.Panels.Count do
  19.     LocalStatusbar.Panels.Add;
  20.  
  21.   w := 0;
  22.   For i := Pred(fStatusbar.Panels.Count) downto 1 do
  23.   begin
  24.     LocalStatusbar.Panels[i].Width := fStatusbar.Panels[i].Width;
  25.     Inc(w, fstatusbar.Panels[i].Width);
  26.   end;
  27.   LocalStatusbar.Panels[0].Width:= Width - w;
  28.  
  29. end;    
  30.  

The PageControl has an OnResize-Event Calculating the TabWidth of the PageControl to widen the tabs to a maximum for optical reasons.
Code: Pascal  [Select][+][-]
  1. // also used for OnResize
  2. procedure TfrmTAViewer.FilterSelectorSizeConstraintsChange(Sender: TObject );
  3. var
  4.   w: Integer;
  5. begin
  6.   w := FilterSelector.Width div 4;
  7.   FilterSelector.Tabwidth := w;
  8. end;
  9.  

The surrounding panels of each TSpinEditEx-Control have an OnResize event for synchronising the positions within the panels, here for StartPos und EndPos TSpinEditEx controls
Code: Pascal  [Select][+][-]
  1. procedure TfrmTAViewer.pnlStartPosResize(Sender: TObject);
  2. var
  3.   w : Integer;
  4.   p : Integer;
  5. begin
  6.   w := lblStartPos.Width + 3 + StartPos.Width;
  7.   p := ((pnlStartPos.Width - w) div 2) + lblStartPos.Width + 3;
  8.   StartPos.Left := p;
  9.   EndPos.Left := p;
  10. end;        
  11.  

There is only one event that can possibly modify the values of the TSpinEditEx-Objects. But it an OnEditingDone event, each Object in the group calls it. But the error occurs even when nothing has been touched, just switch die TAViewer-Page once and resize it., an the Values are changed:
Code: Pascal  [Select][+][-]
  1. procedure TfrmTAViewer.CheckGeneral(Sender: TObject);
  2. begin
  3.   if (StartPos.Value <> StartPos.NullValue) and (EndPos.Value <> EndPos.NullValue) and (EndPos.Value < StartPos.Value) then
  4.       EndPos.Value := StartPos.Value;
  5.  
  6.   if (not StartDate.DateIsNull) and (not EndDate.DateIsNull) and (EndDate.Date < StartDate.Date) then
  7.       EndDate.Date := StartDate.Date;
  8.  
  9.   if (not StartDate.DateIsNull) and (not EndTime.DateIsNull) and (EndTime.Time < StartTime.Time) then
  10.     EndTime.Time := StartTime.Time;
  11.  
  12.   if (StartTaNmbr.Value <> StartTaNmbr.NullValue) and (EndTaNmbr.Value <> EndTaNmbr.NullValue) and (EndTaNmbr.Value < EndTaNmbr.Value) then
  13.       EndTaNmbr.Value := StartTaNmbr.Value;
  14.  
  15.   grpGeneral.GroupChecked := (StartPOS.Value <> StartPos.NullValue) or
  16.                        (EndPos.Value <> EndPos.NullValue) or
  17.                        (not StartDate.DateIsNull) or
  18.                        (not EndDate.DateIsNull) or
  19.                        (not StartTime.DateIsNull) or
  20.                        (not EndTime.DateIsNull) or
  21.                        (StartTaNmbr.Value <> StartTaNmbr.NullValue) or
  22.                        (EndTaNmbr.Value <> EndTaNmbr.NullValue);
  23.   grpGeneral.GroupCheckBoxEnabled:= grpGeneral.GroupChecked;
  24. end;
  25.  

None of the events (except) the last change any values or trigger the TSpinEdit Up/Down Control.
I don't see anything of my code triggering the UP/Down Code of SpinEdits.

But thanks for looking into it anyway  :)

dangersgromit

  • New member
  • *
  • Posts: 8
Hi Zvoni,

you were right, it was one of the OnResize methods, explicitly the one for the 3 search-option-pages. It widens the tabs to be more accessible.
Code: Pascal  [Select][+][-]
  1. // also used for OnResize
  2. procedure TfrmTAViewer.FilterSelectorSizeConstraintsChange(Sender: TObject );
  3. var
  4.   w: Integer;
  5. begin
  6.   w := FilterSelector.Width div 4;
  7.   FilterSelector.Tabwidth := w;
  8. end;
  9.  

Once I commented it out the error is gone.

What I don't understand is why the resize of the "grandparents" tabwidth triggers a text-change in a T(Float)SpinEditEx.

Well, smaller tabs, but error solved.

THANK YOU! :)

wp

  • Hero Member
  • *****
  • Posts: 12756
The OnResize event of a parent does not cause the OnChange event of the (Float)SpinEditEx to fire - see attached demo. The real reason for your issue must be somewhere else in your code. Put a breakpoint in the OnChange event of the (Float)SpinEditEx, do what triggers the issue, and then, when the application stops at the breakpoint, study the Call Stack window to see from where the OnChange was fired.

dangersgromit

  • New member
  • *
  • Posts: 8
Thanks wp.

I tried your idea of setting the OnChange event an then break there. Did something similar myself a while ago, but the stack does not help. 50 steps aren't enough as it seems.
Now that I know it has to do with me setting the tabwidth of "FilterSelector", I don't see it anywhere in the stack.
That's why I never figured out, that it had to do with the OnResize event of the "FilterSelector". And this is why I thought something must be wrong with the SpinEdit.

Code: Text  [Select][+][-]
  1. #0 TFRMTAVIEWER.STARTPOSCHANGE(TFRMTAVIEWER($000000000EBF63E0), TOBJECT($000000000EC0C3E0)) at FilterSurfaceFunctions.inc:273
  2. #1 TCUSTOMABSTRACTGROUPEDEDIT.EDITCHANGE(TCUSTOMABSTRACTGROUPEDEDIT($000000000EC0C3E0)) at groupededit.pp:949
  3. #2 TSPINEDITEXBASE$1$CRC713F463B.EDITCHANGE(TSPINEDITEXBASE$1$CRC713F463B($000000000EC0C3E0)) at spinex.inc:154
  4. #3 TCUSTOMABSTRACTGROUPEDEDIT.INTERNALONEDITCHANGE(TCUSTOMABSTRACTGROUPEDEDIT($000000000EC0C3E0), TOBJECT($000000000EC980D0)) at groupededit.pp:442
  5. #4 TCUSTOMEDIT.CHANGE(TCUSTOMEDIT($000000000EC980D0)) at customedit.inc:625
  6. #5 TCUSTOMMASKEDIT.CHANGE(TCUSTOMMASKEDIT($000000000EC980D0)) at maskedit.pp:1953
  7. #6 TCUSTOMEDIT.TEXTCHANGED(TCUSTOMEDIT($000000000EC980D0)) at customedit.inc:617
  8. #7 TCUSTOMMASKEDIT.TEXTCHANGED(TCUSTOMMASKEDIT($000000000EC980D0)) at maskedit.pp:1938
  9. #8 TCONTROL.CMTEXTCHANGED(TCONTROL($000000000EC980D0), TMESSAGE (45074; 0; 0; 0; 0; 0; TDWORDFILLER ((0, 0, 0, {1 more elements})); 0; 0; TDWORDFILLER ((0, 0, 0, {1 more elements})); 0; 0; TDWORDFILLER ((0, 0, 0, {1 more elements})))) at control.inc:1238
  10. #9 SYSTEM$_$TOBJECT_$__$$_DISPATCH$formal+145 at :0
  11. #10 TCONTROL.WNDPROC(TCONTROL($000000000EC980D0), TMESSAGE (45074; 0; 0; 0; 0; 0; TDWORDFILLER ((0, 0, 0, {1 more elements})); 0; 0; TDWORDFILLER ((0, 0, 0, {1 more elements})); 0; 0; TDWORDFILLER ((0, 0, 0, {1 more elements})))) at control.inc:2304
  12. #11 TWINCONTROL.WNDPROC(TWINCONTROL($000000000EC980D0), TMESSAGE (45074; 0; 0; 0; 0; 0; TDWORDFILLER ((0, 0, 0, {1 more elements})); 0; 0; TDWORDFILLER ((0, 0, 0, {1 more elements})); 0; 0; TDWORDFILLER ((0, 0, 0, {1 more elements})))) at wincontrol.inc:5474
  13. #12 TCUSTOMEDIT.WNDPROC(TCUSTOMEDIT($000000000EC980D0), TMESSAGE (45074; 0; 0; 0; 0; 0; TDWORDFILLER ((0, 0, 0, {1 more elements})); 0; 0; TDWORDFILLER ((0, 0, 0, {1 more elements})); 0; 0; TDWORDFILLER ((0, 0, 0, {1 more elements})))) at customedit.inc:500
  14. #13 TCONTROL.PERFORM(TCONTROL($000000000EC980D0), 45074, 0, 0) at control.inc:1625
  15. #14 TCONTROL.REALSETTEXT(TCONTROL($000000000EC980D0), $000000001648EA28^: '0') at control.inc:5126
  16. #15 TWINCONTROL.REALSETTEXT(TWINCONTROL($000000000EC980D0), $000000001648EA28^: '0') at wincontrol.inc:8383
  17. #16 TCUSTOMEDIT.REALSETTEXT(TCUSTOMEDIT($000000000EC980D0), $000000001648EA28^: '0') at customedit.inc:560
  18. #17 TCUSTOMMASKEDIT.REALSETTEXT(TCUSTOMMASKEDIT($000000000EC980D0), $000000001648EA28^: '0') at maskedit.pp:1366
  19. #18 TCONTROL.SETTEXT(TCONTROL($000000000EC980D0), $000000001648EA28^: '0') at control.inc:5151
  20. #19 TCUSTOMABSTRACTGROUPEDEDIT.REALSETTEXT(TCUSTOMABSTRACTGROUPEDEDIT($000000000EC0C3E0), $000000001648EA28^: '0') at groupededit.pp:920
  21. #20 TCONTROL.SETTEXT(TCONTROL($000000000EC0C3E0), $000000001648EA28^: '0') at control.inc:5151
  22. #21 TSPINEDITEXBASE$1$CRC713F463B.INITIALIZEWND(TSPINEDITEXBASE$1$CRC713F463B($000000000EC0C3E0)) at spinex.inc:210
  23. #22 TWINCONTROL.CREATEWND(TWINCONTROL($000000000EC0C3E0)) at wincontrol.inc:7605
  24. #23 TWINCONTROL.CREATEHANDLE(TWINCONTROL($000000000EC0C3E0)) at wincontrol.inc:7489
  25. #24 TWINCONTROL.HANDLENEEDED(TWINCONTROL($000000000EC0C3E0)) at wincontrol.inc:7936
  26. #25 TWINCONTROL.CREATEWND(TWINCONTROL($000000000EC0B7E0)) at wincontrol.inc:7624
  27. #26 TWINCONTROL.CREATEHANDLE(TWINCONTROL($000000000EC0B7E0)) at wincontrol.inc:7489
  28. #27 TWINCONTROL.HANDLENEEDED(TWINCONTROL($000000000EC0B7E0)) at wincontrol.inc:7936
  29. #28 TWINCONTROL.CREATEWND(TWINCONTROL($000000000EC0B080)) at wincontrol.inc:7624
  30. #29 TWINCONTROL.CREATEHANDLE(TWINCONTROL($000000000EC0B080)) at wincontrol.inc:7489
  31. #30 TWINCONTROL.HANDLENEEDED(TWINCONTROL($000000000EC0B080)) at wincontrol.inc:7936
  32. #31 TWINCONTROL.CREATEWND(TWINCONTROL($000000000EC0A480)) at wincontrol.inc:7624
  33. #32 TWINCONTROL.CREATEHANDLE(TWINCONTROL($000000000EC0A480)) at wincontrol.inc:7489
  34. #33 TWINCONTROL.HANDLENEEDED(TWINCONTROL($000000000EC0A480)) at wincontrol.inc:7936
  35. #34 TWINCONTROL.CREATEWND(TWINCONTROL($000000000EC096E0)) at wincontrol.inc:7624
  36. #35 TWINCONTROL.CREATEHANDLE(TWINCONTROL($000000000EC096E0)) at wincontrol.inc:7489
  37. #36 TWINCONTROL.HANDLENEEDED(TWINCONTROL($000000000EC096E0)) at wincontrol.inc:7936
  38. #37 TWINCONTROL.CREATEWND(TWINCONTROL($000000000EC014C0)) at wincontrol.inc:7624
  39. #38 TSCROLLINGWINCONTROL.CREATEWND(TSCROLLINGWINCONTROL($000000000EC014C0)) at scrollingwincontrol.inc:31
  40. #39 TWINCONTROL.CREATEHANDLE(TWINCONTROL($000000000EC014C0)) at wincontrol.inc:7489
  41. #40 TWINCONTROL.HANDLENEEDED(TWINCONTROL($000000000EC014C0)) at wincontrol.inc:7936
  42. #41 TWINCONTROL.CREATEWND(TWINCONTROL($000000000EC00E00)) at wincontrol.inc:7624
  43. #42 TWINCONTROL.CREATEHANDLE(TWINCONTROL($000000000EC00E00)) at wincontrol.inc:7489
  44. #43 TWINCONTROL.HANDLENEEDED(TWINCONTROL($000000000EC00E00)) at wincontrol.inc:7936
  45. #44 TWINCONTROL.CREATEWND(TWINCONTROL($000000000EC006C0)) at wincontrol.inc:7624
  46. #45 TCUSTOMTABCONTROL.CREATEWND(TCUSTOMTABCONTROL($000000000EC006C0)) at customnotebook.inc:282
  47. #46 TWINCONTROL.CREATEHANDLE(TWINCONTROL($000000000EC006C0)) at wincontrol.inc:7489
  48. #47 TWINCONTROL.HANDLENEEDED(TWINCONTROL($000000000EC006C0)) at wincontrol.inc:7936
  49. #48 TWINCONTROL.HANDLENEEDED(TWINCONTROL($000000000F285970)) at wincontrol.inc:7930
  50. #49 TWINCONTROL.HANDLENEEDED(TWINCONTROL($000000000F286030)) at wincontrol.inc:7930
  51.  

... I tried to come with an example to demonstrate it, but when trying to replicate the error, it never occurs. Just like in your example, everything works fine.
That's why I never dared to bother you and the other heroes in the past.

Well, I'll just remove the "widened" tabs from the code and leave the tabs as the widgetset intends them to be. My users shouldn't have to worry about resetting complex filter combinations only because they've resized the window or the pagecontrol.

 

TinyPortal © 2005-2018