Recent

Author Topic: Radio Buttons cause a "STACK OVERFLOW"  (Read 408 times)

OC DelGuy

  • Full Member
  • ***
  • Posts: 197
Radio Buttons cause a "STACK OVERFLOW"
« on: March 26, 2025, 06:27:44 pm »
Why is there a "STACK OVERFLOW" error here?
When I first click any of the RB's it works fine.  But if I click a different button, then I get the error.

Code: Pascal  [Select][+][-]
  1. unit RadButts;
  2. {$mode objfpc}{$H+}
  3. interface
  4.  
  5. uses
  6.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
  7.  
  8. type
  9.   { TForm1 }
  10.  
  11.   TForm1 = class(TForm)
  12.     Solve: TButton;
  13.     Edit1: TEdit;
  14.     Edit2: TEdit;
  15.     Edit3: TEdit;
  16.     Memo1: TMemo;
  17.     RadioButton: TLabel;
  18.     RadioButton1: TRadioButton;
  19.     RadioButton2: TRadioButton;
  20.     RadioButton3: TRadioButton;
  21.     RadioButton4: TRadioButton;
  22.     RadioButton5: TRadioButton;
  23.     procedure RadioButton1Change(Sender: TObject);
  24.     procedure RadioButton2Change(Sender: TObject);
  25.     procedure RadioButton3Change(Sender: TObject);
  26.     procedure RadioButton4Change(Sender: TObject);
  27.     procedure RadioButton5Change(Sender: TObject);
  28.   end;
  29.  
  30. var
  31.   Form1: TForm1;
  32.  
  33. implementation
  34. {$R *.lfm}
  35. { TForm1 }
  36.  
  37.   procedure TForm1.RadioButton1Change(Sender: TObject);
  38.     begin
  39.       If RadioButton1.Checked=False then
  40.         Begin
  41.           RadioButton1.Checked:=True;
  42.           RadioButton2.Checked:=False;
  43.           RadioButton3.Checked:=False;
  44.           RadioButton4.Checked:=False;
  45.           RadioButton5.Checked:=False;
  46.         End;  { RadioButton1.Checked=False }
  47.     end;  {proc RadioButton1Change}
  48.  
  49.   procedure TForm1.RadioButton2Change(Sender: TObject);
  50.     begin
  51.       If RadioButton2.Checked=False then
  52.         Begin
  53.           RadioButton1.Checked:=False;
  54.           RadioButton2.Checked:=True;
  55.           RadioButton3.Checked:=False;
  56.           RadioButton4.Checked:=False;
  57.           RadioButton5.Checked:=False;
  58.         End;  { RadioButton2.Checked=False }
  59.     end;  {proc RadioButton2Change}
  60.  
  61.   procedure TForm1.RadioButton3Change(Sender: TObject);
  62.     begin
  63.       If RadioButton3.Checked=False then
  64.         Begin
  65.           RadioButton1.Checked:=False;
  66.           RadioButton2.Checked:=False;
  67.           RadioButton3.Checked:=True;
  68.           RadioButton4.Checked:=False;
  69.           RadioButton5.Checked:=False;
  70.         End;  { RadioButton3.Checked=False }
  71.     end;  {proc RadioButton3Change}
  72.  
  73.   procedure TForm1.RadioButton4Change(Sender: TObject);
  74.     begin
  75.       If RadioButton4.Checked=False then
  76.         Begin
  77.           RadioButton1.Checked:=False;
  78.           RadioButton2.Checked:=False;
  79.           RadioButton3.Checked:=False;
  80.           RadioButton4.Checked:=True;
  81.           RadioButton5.Checked:=False;
  82.         End;  { RadioButton4.Checked=False }
  83.     end;  {proc RadioButton4Change}
  84.  
  85.   procedure TForm1.RadioButton5Change(Sender: TObject);
  86.     begin
  87.       If RadioButton5.Checked=False then
  88.         Begin
  89.           RadioButton1.Checked:=False;
  90.           RadioButton2.Checked:=False;
  91.           RadioButton3.Checked:=False;
  92.           RadioButton4.Checked:=False;
  93.           RadioButton5.Checked:=True;
  94.         End;  { RadioButton5.Checked=False }
  95.     end;  {proc RadioButton5Change}
  96.  
  97. end.  {Implementation}
  98.  
Free Pascal Lazarus Version #: 2.2.4
Date: 24 SEP 2022
FPC Version: 3.2.2
Revision: Lazarus_2_2_4
x86_64-win64-win32/win64

Jorg3000

  • Jr. Member
  • **
  • Posts: 75
Re: Radio Buttons cause a "STACK OVERFLOW"
« Reply #1 on: March 26, 2025, 07:07:10 pm »
Hi!
You create a recursion because you always create a new change in the change event (setting .Checked again).
This causes the change function to be called thousands of times until the stack overflows.

Do not make any changes to .Checked of the same control in a Change event.


paweld

  • Hero Member
  • *****
  • Posts: 1354
Re: Radio Buttons cause a "STACK OVERFLOW"
« Reply #2 on: March 26, 2025, 07:11:09 pm »
The TradioButton component has it that changing one of them to selected automatically deselects the previously selected one - this applies to all RBs in the group (located on the same parent component).
Thus, all events in your code are unnecessary.

More info: https://wiki.lazarus.freepascal.org/TRadioButton
Best regards / Pozdrawiam
paweld

cdbc

  • Hero Member
  • *****
  • Posts: 2086
    • http://www.cdbc.dk
Re: Radio Buttons cause a "STACK OVERFLOW"
« Reply #3 on: March 26, 2025, 07:14:02 pm »
Hi
As @paweld so correctly says it, thanks mate  :)
Meanwhile I made a small example for you, to look at and learn from...

eta: For others that can't bother to download, here's the pas-file:
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
  9.   ComCtrls;
  10.  
  11. type
  12.  
  13.   { TfrmMain }
  14.   TfrmMain = class(TForm,IFPObserver)
  15.     Panel1: TPanel;
  16.     RadioButton1: TRadioButton;
  17.     RadioButton2: TRadioButton;
  18.     RadioButton3: TRadioButton;
  19.     RadioButton4: TRadioButton;
  20.     stbInfo: TStatusBar;
  21.   private
  22.     procedure FPOObservedChanged(ASender: TObject;
  23.                                  Operation: TFPObservedOperation;
  24.                                  {%H-}Data: Pointer);
  25.     procedure HandleClick(aSender: TObject);
  26.   public
  27.     procedure AfterConstruction; override;
  28.     procedure BeforeDestruction; override;
  29.   end;
  30.  
  31. var
  32.   frmMain: TfrmMain;
  33.  
  34. implementation
  35.  
  36. {$R *.lfm}
  37.  
  38. { TfrmMain }
  39. procedure TfrmMain.FPOObservedChanged(ASender: TObject;
  40.                                       Operation: TFPObservedOperation;
  41.                                       Data: Pointer);
  42. begin
  43.   case Operation of
  44.     ooChange: begin
  45.                 if ASender is TComponent then
  46.                   stbInfo.SimpleText:= TComponent(ASender).Name + ' is chosen :)';
  47.               end;
  48.   end;
  49. end;
  50.  
  51. procedure TfrmMain.HandleClick(aSender: TObject);
  52. begin
  53.   (aSender as TRadioButton).FPONotifyObservers(aSender,ooChange,nil);
  54. end;
  55.  
  56. procedure TfrmMain.AfterConstruction;
  57. begin
  58.   inherited AfterConstruction;
  59.   RadioButton1.FPOAttachObserver(Self);
  60.   RadioButton1.OnClick:= @HandleClick;
  61.   RadioButton2.FPOAttachObserver(Self);  
  62.   RadioButton2.OnClick:= @HandleClick;
  63.   RadioButton3.FPOAttachObserver(Self);
  64.   RadioButton3.OnClick:= @HandleClick;
  65.   RadioButton4.FPOAttachObserver(Self);
  66.   RadioButton4.OnClick:= @HandleClick;  
  67.   RadioButton3.Checked:= true;
  68. end;
  69.  
  70. procedure TfrmMain.BeforeDestruction;
  71. begin /// important to remember detaching observers to avoid AVs
  72.   RadioButton1.FPODetachObserver(Self);
  73.   RadioButton2.FPODetachObserver(Self);
  74.   RadioButton3.FPODetachObserver(Self);
  75.   RadioButton4.FPODetachObserver(Self);
  76.   inherited BeforeDestruction;
  77. end;
  78.  
  79. end.
  80.  
  81.  

Regards Benny
« Last Edit: March 26, 2025, 07:32:08 pm by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

jamie

  • Hero Member
  • *****
  • Posts: 6873
Re: Radio Buttons cause a "STACK OVERFLOW"
« Reply #4 on: March 26, 2025, 09:29:43 pm »
maybe you can use this.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.RadioButton1Change(Sender: TObject);
  2. begin
  3.   With TRadioButton(Sender) do
  4.    Begin
  5.       If Tag = 0 Then Tag := 1 else Exit; //Busy state.
  6.       // Do your code here.
  7.      Tag := 0;
  8.    end;
  9. end;                                          
  10.  

That will prevent a loop.
Jamie
The only true wisdom is knowing you know nothing

 

TinyPortal © 2005-2018