Recent

Author Topic: [SOLVED] Set OnClick event on dynamically created button  (Read 532 times)

Lurgainn

  • New member
  • *
  • Posts: 7
[SOLVED] Set OnClick event on dynamically created button
« on: December 06, 2024, 04:43:31 pm »
Sorry, I know that this is a already disccussed argument, but I really need a tip because I'm not able to understand what I'm doing wrong.
I created a unit WITHOUT any form (so no class exists), to put inside all necessary code to dynamically create a new form with some components, one of them is a button, and obviously I want to assign a procedure to this button.
This unit will be used from other units that have a form, by insert "UnitFormDeluxeAbout" into uses, and calling the procedure "CreateFormDeluxeAbout" and assigning tha calling form as parent.

My test code is this:
Code: Pascal  [Select][+][-]
  1. unit UnitFormDeluxeAbout;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.     Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  9.     Buttons, StdCtrls;
  10.  
  11. procedure CreateFormDeluxeAbout(form_parent: TForm);
  12.  
  13. implementation
  14.  
  15. var
  16.     DeluxeFormAbout: TForm;
  17.     DeluxeFormAboutCloseButton: TButton;
  18.  
  19. procedure DeluxeFormAboutCloseButtonClick(Sender: TObject); forward;
  20.  
  21. procedure CreateFormDeluxeAbout(form_parent: TForm);
  22. begin
  23.     DeluxeFormAbout := TForm.Create(form_parent);
  24.     DeluxeFormAbout.SetBounds(100, 100, 220, 150);
  25.     DeluxeFormAbout.Caption := 'My dynamic created form';
  26.     DeluxeFormAbout.Parent := form_parent;
  27.  
  28.     DeluxeFormAboutCloseButton := TButton.Create(DeluxeFormAbout);
  29.     DeluxeFormAboutCloseButton.Caption := 'Close my form';
  30.     DeluxeFormAboutCloseButton.SetBounds(10, 10, 200, 30);
  31.     DeluxeFormAboutCloseButton.Parent := DeluxeFormAbout;
  32.  
  33.     DeluxeFormAboutCloseButton.OnClick := @DeluxeFormAboutCloseButtonClick;
  34.  
  35.     DeluxeFormAbout.ShowModal;
  36.  
  37.     FreeAndNil(DeluxeFormAbout);
  38. end;
  39.  
  40. procedure DeluxeFormAboutCloseButtonClick(Sender: TObject);
  41. begin
  42.     ShowMessage('Attention, closing my dynamically created form!');
  43.     if Sender is TButton then
  44.         TForm(TButton(Sender).Parent).Close;
  45. end;
  46.  
  47. end.
  48.  

But when I build this unit, I get this error:
unitformdeluxeabout.pas(33,43) Error: Incompatible types: got "<address of procedure(TObject);Register>" expected "<procedure variable type of procedure(TObject) of object;Register>"

Is there a simple way to solve this problem?

Thanks so much for any help
« Last Edit: December 06, 2024, 06:18:49 pm by Lurgainn »

cdbc

  • Hero Member
  • *****
  • Posts: 1759
    • http://www.cdbc.dk
Re: Set OnClick event on dynamically created button
« Reply #1 on: December 06, 2024, 05:09:33 pm »
Hi
I dunno if it's simple, but here goes:
Code: Pascal  [Select][+][-]
  1. unit UnitFormDeluxeAbout;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.     Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  9.     Buttons, StdCtrls;
  10.  
  11. procedure CreateFormDeluxeAbout(form_parent: TForm);
  12.  
  13. implementation
  14. type
  15.   THack = object
  16.     procedure DeluxeFormAboutCloseButtonClick(Sender: TObject);
  17.   end;
  18. var
  19.     DeluxeFormAbout: TForm;
  20.     DeluxeFormAboutCloseButton: TButton;
  21.     EventH: THack;
  22.  
  23.  
  24. procedure CreateFormDeluxeAbout(form_parent: TForm);
  25. begin
  26.     DeluxeFormAbout := TForm.Create(form_parent);
  27.     DeluxeFormAbout.SetBounds(100, 100, 220, 150);
  28.     DeluxeFormAbout.Caption := 'My dynamic created form';
  29.     DeluxeFormAbout.Parent := form_parent;
  30.  
  31.     DeluxeFormAboutCloseButton := TButton.Create(DeluxeFormAbout);
  32.     DeluxeFormAboutCloseButton.Caption := 'Close my form';
  33.     DeluxeFormAboutCloseButton.SetBounds(10, 10, 200, 30);
  34.     DeluxeFormAboutCloseButton.Parent := DeluxeFormAbout;
  35.  
  36.     DeluxeFormAboutCloseButton.OnClick := @EventH.DeluxeFormAboutCloseButtonClick;
  37.  
  38.     DeluxeFormAbout.ShowModal;
  39.  
  40.     FreeAndNil(DeluxeFormAbout);
  41. end;
  42.  
  43. procedure THack.DeluxeFormAboutCloseButtonClick(Sender: TObject);
  44. begin
  45.     Application.ShowMessage('Attention, closing my dynamically created form!');
  46.     if Sender is TButton then
  47.         TForm(TButton(Sender).Parent).Close;
  48. end;
  49.  
  50. end.
  51.  
Quick'n'Dirty ...but something along these lines  :D
Regards Benny
« Last Edit: December 06, 2024, 06:07:57 pm by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Lurgainn

  • New member
  • *
  • Posts: 7
Re: Set OnClick event on dynamically created button
« Reply #2 on: December 06, 2024, 06:18:18 pm »
Thanks so much !!!!

I had no idea that the OnClick procedure must be defined as an Object's method.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1452
    • Lebeau Software
Re: Set OnClick event on dynamically created button
« Reply #3 on: December 06, 2024, 06:30:02 pm »
Code: Pascal  [Select][+][-]
  1. var
  2.     DeluxeFormAbout: TForm;
  3.     DeluxeFormAboutCloseButton: TButton;
  4.     EventH: THack;

You are not creating the EventH object, so DeluxeFormAboutCloseButtonClick() method will be called on an invalid object.  This can be find if you never access the method's Self parameter, but it is something to be aware of.

I had no idea that the OnClick procedure must be defined as an Object's method.

Technically, you CAN use a standalone procedure, butt you have to tweak the approach a little:

Code: Pascal  [Select][+][-]
  1. procedure DeluxeFormAboutCloseButtonClick(Self: Pointer; Sender: TObject); forward;
  2.      
  3. procedure CreateFormDeluxeAbout(form_parent: TForm);
  4. var
  5.   ClickHandler: TNotifyEvent;
  6. begin
  7.   ...
  8.      
  9.   TMethod(ClickHandler).Code := @DeluxeFormAboutCloseButtonClick;
  10.   TMethod(ClickHandler).Data := ...; // whatever you want the Self parameter to point at...
  11.   DeluxeFormAboutCloseButton.OnClick := ClickHandler;
  12.  
  13.   ...    
  14. end;
  15.      
  16. procedure DeluxeFormAboutCloseButtonClick(Self: Pointer; Sender: TObject);
  17. begin
  18.   ...
  19. end;
     
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

cdbc

  • Hero Member
  • *****
  • Posts: 1759
    • http://www.cdbc.dk
Re: [SOLVED] Set OnClick event on dynamically created button
« Reply #4 on: December 06, 2024, 06:54:53 pm »
Hi Remy
Code: Pascal  [Select][+][-]
  1. type
  2.   THack = object
  3.     procedure DeluxeFormAboutCloseButtonClick(Sender: TObject);
  4.   end;
It's NOT a class!
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

 

TinyPortal © 2005-2018