Recent

Author Topic: [workaround found] How to get the sender within a frame?  (Read 1717 times)

n7800

  • Hero Member
  • *****
  • Posts: 650
  • Lazarus IDE contributor
    • GitLab profile
Re: [workaround found] How to get the sender within a frame?
« Reply #15 on: July 02, 2025, 01:53:23 pm »
Both TAction and TSpeedButton are TComponent, so for both can be used (although it is advisable to check via "is"):

Code: Pascal  [Select][+][-]
  1. TComponent(Sender).Name
  2.  

In general, for debugging, the ClassName property of the TObject itself can be used:

Code: Pascal  [Select][+][-]
  1. Sender.ClassName
  2.  

cdbc

  • Hero Member
  • *****
  • Posts: 2684
    • http://www.cdbc.dk
Re: [workaround found] How to get the sender within a frame?
« Reply #16 on: July 02, 2025, 01:59:59 pm »
Hi
@Nicole: You just need to study 'PolyMorphism' in the context of classes.
Basically you can stuff any descendant of 'TObject' into the '(Sender: TObject)' parameter.
The 'As' & 'Is' operators are made for dealing with PolyMorphism (the ability to assume more forms or shapes). as @Thaddy*) correctly wrote.
Regards Benny

eta: *) and n7800  :D
« Last Edit: July 02, 2025, 02:03:21 pm by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

Thaddy

  • Hero Member
  • *****
  • Posts: 18791
  • Glad to be alive.
Re: [workaround found] How to get the sender within a frame?
« Reply #17 on: July 02, 2025, 02:09:39 pm »
@n7800
OP's specification is which button, not which button class.
Recovered from removal of tumor in tongue following tongue reconstruction with a part from my leg.

Nicole

  • Hero Member
  • *****
  • Posts: 1308
Re: [workaround found] How to get the sender within a frame?
« Reply #18 on: July 02, 2025, 03:14:17 pm »
now it is about sports  ;)

"TComponent(Sender).Name"
is a good idea, but will not work as sender, because this gives a string, not an object

"if....is..."
is good an idea, but does not change under the line the value passed

And yes, I read the beginners stuff about senders, loooong ago. And forgot it all in the meanwhile.
If sender is alike an usual parameter, pls tell me:
- Why does every button click event enforce this parameter, -  mostly not used?
- Why must I set in the preferences, that "not used" is not shown in this case?
- Why can't I add an additional parameter to a button-click-event or change it?
- What is this "sender" good for, if this idiot of a button, does not even know his own name?



Thaddy

  • Hero Member
  • *****
  • Posts: 18791
  • Glad to be alive.
Re: [workaround found] How to get the sender within a frame?
« Reply #19 on: July 02, 2025, 03:52:11 pm »
sender IS the object instance....It happens to have a property called "name"....
(You might think a little bit longer about how things actually work...  ::) )

It is not a type, it is the instance, so you can manipulate all properties and events.
Provided the proper cast.
« Last Edit: July 02, 2025, 03:57:51 pm by Thaddy »
Recovered from removal of tumor in tongue following tongue reconstruction with a part from my leg.

rvk

  • Hero Member
  • *****
  • Posts: 6953
Re: [workaround found] How to get the sender within a frame?
« Reply #20 on: July 02, 2025, 04:04:16 pm »
- Why does every button click event enforce this parameter, -  mostly not used?
Because it's the most useful parameter in a click event :)
You can use the same event for multiple classes (pointing to the same click event) and your onclick can then determine via Sender from which one it comes from. You can use ClassName to determine that and after that you can use TClass(Sender).xxx to access everything from that sender.

- Why can't I add an additional parameter to a button-click-event or change it?
You can. But if you want to do that, you need to override the DoClick procedure of the component first to add the parameter in the "if assigned(fonclick) do fonclick(sender, myparam);".

- What is this "sender" good for, if this idiot of a button, does not even know his own name?
%) It does know it's own name. Why do you think it doesn't?

What exactly do you want to accomplish? Maybe show some code. I think it can be done much much simpler than what you are trying to do.
« Last Edit: July 02, 2025, 04:07:18 pm by rvk »

Nicole

  • Hero Member
  • *****
  • Posts: 1308
Re: [workaround found] How to get the sender within a frame?
« Reply #21 on: July 02, 2025, 05:25:23 pm »
@rvk
This was exactly the problem! I wanted to do what you suggest: Use one method from several buttons called. After having put those buttons into a frame, they did not "know their names any more". They said the name of the frame instead of their own.

After fuzzing around, they "knew more": they said, they were "SpeedButtons", - but not which one!

All the ideas suggested in this thread I have tried before, because they sound logic. They did not work.
Before posting, I tried for at least an hour to make those buttons passing their own names to the function (what they did fine, before having been shifted to this frame). Be aware, if you need 4 lines of code to pass just a parameter, this is no solution any more.

And one more sender bashing: Why can't I see in the watch-list the sender's value? I remember this was the same trouble in Delphi. I stuck to it: Sender is not my favourite.

rvk

  • Hero Member
  • *****
  • Posts: 6953
Re: [workaround found] How to get the sender within a frame?
« Reply #22 on: July 02, 2025, 07:34:33 pm »
@rvk
This was exactly the problem! I wanted to do what you suggest: Use one method from several buttons called. After having put those buttons into a frame, they did not "know their names any more". They said the name of the frame instead of their own.
Ha, now I know where you are going wrong in your reasoning.

You do understand Sender is a TObject and TObject is actually just a pointer?? It hold the base class of all classes. So it can be anything.

But... TObject doesn't have a property "name". That is only introduced in TComponent.
https://www.freepascal.org/docs-html/rtl/classes/tcomponent.html

So... although TObject can POINT to a TButton, you can't access it until you actually cast it to TButton (or TComponent as it's the first time .name is introduced).

So consider (and test) the following code:
It checks it the Sender is a TComponent (or descendant) and only then shows you the TComponent.Name property.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   if Sender is TComponent then
  4.     Showmessage(TComponent(Sender).Name);
  5. end;

Does that make it more clear.

So you can create one event handler, attach it to lots of different TComponent descendants (TButton, TForm, TSpeedButton etc) and with just this code you can retrieve the .Name.

You can also do other things if you know the class
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   if Sender is TComponent then
  4.     Showmessage(TComponent(Sender).Name);
  5.   if Sender is TForm then
  6.     Showmessage(TForm(Sender).Name + ' has a left property of ' + TForm(Sender).Left.ToString);
  7. end;

Try it... connect this Button1Click (I didn't rename it so you can just reuse the same event) to the Form (by the pulldown choosing Button1Click for the OnClick in the Form OnClick event).

When clicking the TForm (just click anywhere on the form) you first get the name (because TForm is also a TComponent) and then you get the "Form1 has a left property of 123".

I hope this clarify some things.
« Last Edit: July 02, 2025, 07:38:40 pm by rvk »

Nicole

  • Hero Member
  • *****
  • Posts: 1308
Re: [workaround found] How to get the sender within a frame?
« Reply #23 on: July 02, 2025, 07:59:51 pm »
Thank you for the explanation. To repeat this, is a good idea.

n7800

  • Hero Member
  • *****
  • Posts: 650
  • Lazarus IDE contributor
    • GitLab profile
Re: [workaround found] How to get the sender within a frame?
« Reply #24 on: July 02, 2025, 10:45:07 pm »
@n7800
OP's specification is which button, not which button class.

As I mentioned, I meant for debugging purposes only. Calling ClassName is easier than listing all possible class variants via "if Sender is ... then ... else if Sender is ...".

n7800

  • Hero Member
  • *****
  • Posts: 650
  • Lazarus IDE contributor
    • GitLab profile
Re: [workaround found] How to get the sender within a frame?
« Reply #25 on: July 02, 2025, 10:57:02 pm »
This was exactly the problem! I wanted to do what you suggest: Use one method from several buttons called. After having put those buttons into a frame, they did not "know their names any more".

Wait, I don't get it... If you added a button to a frame, and the frame to your form, how do you want to recognize the button by name? There can be any number of frames in a form, and inside each there will be buttons with the same names...

They said the name of the frame instead of their own.

I don't understand how Sender could return a frame instead of a button?

After fuzzing around, they "knew more": they said, they were "SpeedButtons", - but not which one!

What "fuzzing around"? How did they say? It seems my translator can't handle it ))

It would be better if you actually attached a simple project of what you want to achieve.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1575
    • Lebeau Software
Re: [workaround found] How to get the sender within a frame?
« Reply #26 on: July 03, 2025, 03:56:20 am »
This was exactly the problem! I wanted to do what you suggest: Use one method from several buttons called. After having put those buttons into a frame, they did not "know their names any more". They said the name of the frame instead of their own.

That is because you redesigned your UI but did not pay attention to your new hierarchy or to what the new Self actually points at.  You are not asking for the name of the button at all.  You are asking for the name of the Frame instead.

Self is a hidden pointer inside of a class method. It points at an instance of the class which owns that method.

SpeedButton_TagesberichtErstellenClick() is a method of the TFrame_BerichteF class, and therefore its Self pointer always points at an instance of TFrame_BerichteF.  It does not matter what kind of object event SpeedButton_TagesberichtErstellenClick() is assigned to.  Its Self will always point at the owning TFrame_BerichteF object.

That's why events have a Sender parameter, to point at the object which is triggering the event.

This flexibility is what allows multiple object events to be assigned a shared event handler, eg:

Code: Pascal  [Select][+][-]
  1. SpeedButton1.OnClick := SpeedButton_TagesberichtErstellenClick;
  2. SpeedButton2.OnClick := SpeedButton_TagesberichtErstellenClick;
  3. ...

Or for multiple objects to assign their own handler to a shared event, eg:

Code: Pascal  [Select][+][-]
  1. if SomeCondition then
  2.   SpeedButton1.OnClick := Frame1.SpeedButton_TagesberichtErstellenClick
  3. else if SomeOtherCondition then
  4.   SpeedButton1.OnClick := Frame2.SpeedButton_TagesberichtErstellenClick
  5. else ...

After fuzzing around, they "knew more": they said, they were "SpeedButtons", - but not which one!

Sender is a pointer.  It points at the object which triggered the event.  You can use that pointer to access members of that object, eg:

Code: Pascal  [Select][+][-]
  1. procedure TFrame_BerichteF.SpeedButton_TagesberichtErstellenClick(Sender: TObject);
  2. begin
  3.   ShowMessage(TSpeedButton(Sender).Name);
  4. end;

Or even to just compare it to object pointers directly, eg:

Code: Pascal  [Select][+][-]
  1. procedure TFrame_BerichteF.SpeedButton_TagesberichtErstellenClick(Sender: TObject);
  2. begin
  3.   if Sender = SpeedButton1 then
  4.     ...
  5.   else if Sender = SpeedButton2 then
  6.     ...
  7. end;

All the ideas suggested in this thread I have tried before, because they sound logic. They did not work.

Yes, they do work. You are just not applying them correctly to your situation.

Why can't I see in the watch-list the sender's value?

Because the Sender is itself just a raw TObject pointer, so all you can see from it is a memory address and no properties. To see anything more meaningful, you have to type-cast it to the correct derived type in order to access its properties.

I always program through actions when writing a user interface and that does not work: Sender is TAction, not TSpeedButton.

Then cast the Sender to TAction and use its ActionComponent property to know which component triggered the action.
« Last Edit: July 03, 2025, 04:20:22 am by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

egsuh

  • Hero Member
  • *****
  • Posts: 1760
Re: [workaround found] How to get the sender within a frame?
« Reply #27 on: July 03, 2025, 07:43:05 am »
You should be able to identify the Sender, if OnClick event is defined (not Action).

Code: Pascal  [Select][+][-]
  1.     procedure TFrame_BerichteF.SpeedButton_TagesberichtErstellenClick(Sender: TObject);
  2.     begin
  3.          if Sender = SpeedButton1 then  Berichte_erstellen('Daily Report')
  4.          eles if Sender = SpeedButton2 then Berichte_erstellen('Weekly Report')
  5.          eles if Sender = SpeedButton3 then Berichte_erstellen('Monthly Report')
  6.          eles ShowMessage (Sender.className + ' should not call me');
  7.     end;

If this code does "ShowMessage", then please let us know Sender.className.

creaothceann

  • Sr. Member
  • ****
  • Posts: 279
Re: [workaround found] How to get the sender within a frame?
« Reply #28 on: July 03, 2025, 08:31:05 am »
You could also assign IDs to the Tags and do this:

Code: [Select]
procedure TFrame_BerichteF.SpeedButton_OnClick_TagesberichtErstellen(Sender : TObject);
begin
case (Sender as TComponent).Tag of
1:   Berichte_erstellen('Daily'   + ' Report');
2:   Berichte_erstellen('Weekly'  + ' Report');
3:   Berichte_erstellen('Monthly' + ' Report');
else raise Exception.Create(Sender.ClassName + ' should not call me');
end;
end;

If this code does "ShowMessage"
As it is now it'll show a compilation error :)
« Last Edit: July 03, 2025, 08:32:36 am by creaothceann »

 

TinyPortal © 2005-2018