> You can't "send" an event.
Yes you can.
> There's the sender of the message, that's windows
Delphi events aren't Windows messages. Don't confuse the two -- these
are two very different things.
> the creator of the event, that's the user
Now you are confusing event-handler methods with events. These also
are two different things. The user creates an event-handler method,
not an event.
> In the (Sender: TObject) parameter, is Sender the button ?
Yes, Sender is the specific instance of the TButton class which
triggered (or "sent") then event.
> What would Sender be if I want to use the same code I wrote for a
> button click on Form1, from the button click handler of a button on Form2 ?
Depends on which button was clicked. Here's an example which should
elucidate. Notice that I've assigned the exact same event-handler
method (SharedButtonClick) to the OnClick event of two different
TButton instances:
>>>>
unit Unit1;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
procedure SharedButtonClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
Button1.Caption := 'This is Button1';
Button1.OnClick := SharedButtonClick;
Button2.Caption := 'This is Button2';
Button2.OnClick := SharedButtonClick;
end;
procedure TForm1.SharedButtonClick(Sender: TObject);
begin
ShowMessage((Sender as TButton).Caption);
end;
end.
<<<<
When you click the first button, the message "This is Button1"
displays. When you click the second button, the message "This is
Button2", as expected, displays. That is because when a button
instance (Button1 or Button2) triggers its OnClick event, it passes a
pointer to its self as the Sender parameter. So the Sender parameter
will always have a reference to the instance of the object which
triggered the event -- the event's "sender".
> Do you always use "self" when calling an event handler you wrote?
No, not at all, Self is a different concept entirely. People
frequently confuse "Sender" and "Self" but it is important to realize
that these are two totally different things.
Sender is simply a name of a parameter passed to many event-handler
methods -- the parameter could have been called anything else.
Event-handler methods are just normal methods, and Sender just happens
to be a common name of the first parameter passed to event-handler
methods.
Self is a special language keyword which means "the instance through
which the method is being called." The definition of Self depends on
context -- in your example:
procedure TMainForm.Edit1Change(Sender: TObject);
begin
...
Form1.Button1Click(self); //call that procedure
...
end;
Since you used Self within a method of TMainForm, you will have passed
a reference to the _TMainForm instance_ to the Button1Click
event-handler, not the Button1 instance as would be expected. This
sort of (mis-)use of Self will probably result in problems in your
code. What you probably mean is:
procedure TMainForm.Edit1Change(Sender: TObject);
begin
...
Form1.Button1Click(Button1); //call that procedure
...
end;
> Why does this parameter exist, anyway?
Because a single event-handler method can be used by multiple object
instances (even including objects of different class types), and the
Sender parameter allows the event-handler method take appropriate
action depending on which object instance triggered (or "sent") the
event.
--
Rick Rogers (TeamB) | Fenestra Technologies
http://www.fenestra.com/
"Notifications use the type TNotifyEvent, which carries only one
parameter, the sender of the event."
To me, "sender of the event" doesn't make any sense. You can't "send" an
event. There's the sender of the message, that's windows; the creator
of the event, that's the user; and the object to which the event
occured, the button that was clicked on. In the (Sender: TObject)
parameter, is Sender the button ? How is it a "sender"?
What would Sender be if I want to use the same code I wrote for a button
click on Form1, from the button click handler of a button on Form2 ?
Is the following correct?:
procedure TMainForm.Edit1Change(Sender: TObject);
begin
...
Form1.Button1Click(self); //call that procedure
...
end;
Do you always use "self" when calling an event handler you wrote? What
else can it be?
Why does this parameter exist, anyway? It's just a procedure that is
automatically called when an event occurs.. A kind of an interrupt
handler... (?)
It's not like there was just one interrupt handler handling an interrupt
that can be generated by different sources, and it has to find out who
generated it... because you can write different code for every single
button, so you're writing as many dedicated handlers as there are
sources.
Thanks for helping clear up the windows (delphi?) 'clouds'
Habib Debs
Let's say you have three buttons all set to use the exact same OnClick
event handler. The sender parameter tells the event handler which of
the three buttons actually called it.
-Mike
I was actually using the plain english concept of "event" when I said it
can't be "sent", and I was limiting that concept a bit when I said the
creator of the event is the user (the clicker of the button) since
internal processes can also trigger events.
I understand now that the 'Sender' parameter is necessary because,
contrary to what I said in my first post, it is possible to use one
handler to handle different objects' events, and in that case it must
know which object the event occured to, or where it was called from.
But I still don't see the concept of delphi 'event' you're speaking of.
I'm new to windows programming, but what I've understood until now tends
to indicate that windows programs (even delphi) typically don't do
anything until windows sends them a message (an event occurs, in the
english sense). Most of the delphi component events seem to be simple
reflections of the windows messages. And even when a component invents a
new event, it is based on a windows message somewhere. After all,
they're just windows programs...
Of course you can say that delphi is not just a windows programming
tool, and that it is a world in its own, but I'm already struggeling
with new, to me sometimes totaly unnecessary concepts (I have a hardware
backgound) that make the poor CPU and its memory seem so complicated...
<g> (but that deserves a discussion by itself, and perhaps not in this
newsgroup).
Back to delphi:
> procedure TMainForm.Edit1Change(Sender: TObject);
> begin
> ...
> Form1.Button1Click(self); //call that procedure
> ...
> end;
>
> Since you used Self within a method of TMainForm, you will have passed
> a reference to the _TMainForm instance_ to the Button1Click
> event-handler, not the Button1 instance as would be expected. This
> sort of (mis-)use of Self will probably result in problems in your
> code.
Isn't 'self' in the example above really a reference to Edit1, rather
than TMainForm, since the call came from an Edit1 method?
> > What would Sender be if I want to use the same code I wrote for a
> > button click on Form1, from the button click handler of a button on Form2 ?
>
> Depends on which button was clicked.
Here I meant if I want to call the Form1.Button1Click handler _from_ the
Form2.Button2Click handler. But you answered that earlier, so I guess
it would be:
Form1.Button1Click(Button1)
Right?
Am I right to say that if my Form1.Button1Click handler doesn't use the
Sender parameter, then it doesn't matter in any way, what sender
parameter I pass to it (as long as it's an object)? Or does any other
'hidden' code use this parameter?
Thanks.
Habib
> Most of the delphi component events seem to be simple
> reflections of the windows messages.
Many Delphi events are based on Windows messages, but by no means all.
> And even when a component invents a new event, it is based on a
> windows message somewhere.
Not necessarily true. Probably most Delphi events aren't related to
Windows messages in the slightest -- for example all of the events in
the TTable and TQuery components.
> After all, they're just windows programs...
Delphi programs aren't simply Windows programs -- they also
(typically) include OOP code in the form of the Visual Component
Library (VCL), and/or custom-built classes, all of which can define,
trigger, and respond to their own events without using the Windows
messaging system.
> Isn't 'self' in the example above really a reference to Edit1, rather
> than TMainForm, since the call came from an Edit1 method?
No, not at all, Self is the TMainForm instance, as I correctly stated.
Look closely at the method declaration:
procedure TMainForm.Edit1Change(Sender: TObject);
^^^^^^^^^^
begin
Form1.Button1Click(self);
end;
The "TMainForm." part of the method declaration indicates that this is
indeed a method of the TMainForm class -- it isn't a method of a TEdit
class. So Self in this method would refer to the current instance of
TMainForm.
The TMainForm.Edit1Change method is assigned to the event handler of
an TEdit instance called Edit1, but you should understand that it
still is a method of the TMainForm class, and this method could be
assigned to any number (zero and up) of events, in TEdit or any other
class. Think of events like any other property -- you can assign the
same value to many different properties.
Edit1Change is a method (of TMainForm) which is type-compatible with
TNotifyEvent and can be assigned to any event which is declared as
TNotifyEvent (such as TForm.OnPaint, TFont.OnChange, TImage.OnClick).
There are literally hundreds of events in the VCL which are declared
as TNotifyEvent, and the Edit1Change method could be assigned to any
of them.
This is called "delegation" in OOP terms. In this case, TMainForm is
actually providing an event-handler method for another class -- the
TEdit class has an OnChange event which allows it to delegate
responsibility for responding to the event to any other class,
regardless of type or origin.
> Form1.Button1Click(Button1)
This would be normal, but the meaning of Sender is up to your code.
Typically, you wouldn't invoke the event-handler method like this
directly, instead you would do this:
Form1.Button1.Click;
Which would automatically invoke Button1's current OnClick
event-handler method, if there is any.
> Am I right to say that if my Form1.Button1Click handler doesn't use the
> Sender parameter, then it doesn't matter in any way, what sender
> parameter I pass to it
Correct. Sender is there for the event-handler method's convenience.
If the event handler doesn't use it, then its value doesn't matter.
This is just like any other routine -- if the routine never uses the
parameter, then what is passed as the parameter doesn't matter much.
You've truly been very helpful. It's very clear now. Thank you for
your time!
Regards,
Habib Debs
Paris
BTW: fenestra means "window" in italian ?
> BTW: fenestra means "window" in italian ?
Very good, I think so. It certainly means "window" in Latin, which is
why I chose it for a company name.
> Probably most Delphi events aren't related to
> Windows messages in the slightest
BTW: This should read "Many -- probably most -- Delphi events aren't
related to Windows messages in the slightest".
Form1.Button1Click(Button1)
But to be truly safe it should be
With Form1.Button1 do
If Assigned(OnClick) then OnClick(Button1);
Because the first version would cause an exception if the OnClick event
handler for Button1 hadn't already been assigned. The second version checks
that it has been assigned before calling it with the proper control passed
as Sender.
H. Debs wrote in message <36058592...@compuserve.com>...
>Extract from Delphi4 Help:
>Is the following correct?:
> With Form1.Button1 do
> If Assigned(OnClick) then OnClick(Button1);
Right, but Form1.Button1.Click; is simpler and does the same thing.
BTW, is there anything in a class that you can generically pass instead of
the name?
I mean
With Form1.Button1 do
If Assigned(OnClick) then OnClick(Button1);
requires the second line to be non-generic because I have to pass the
Button1 as Sender. If there was only a generic name for the object instance
that could be revealed by the With.
Rick Rogers (TeamB) wrote in message
<3619439d...@forums.borland.com>...
>On Mon, 5 Oct 1998 13:38:08 -0500, "Mark Reichert"
>
> The one you give below only works with a public DoWhatever
> that calls the event handler.
I'm sorry, I don't follow your question. Calling:
Button1.Click;
Will execute the event handler, if any, with the current instance
(Button1) passed as the parameter. That's because TControl.Click looks
like this:
procedure TControl.Click;
begin
if Assigned(FOnClick) then FOnClick(Self);
end;
This is much safer, clearer, and better than testing for and invoking
the event-handler yourself. There really is no valid reason not to use
the Click method -- that is why it exists. Using the Click method is
totally safe and totally generic.
Rick Rogers (TeamB) wrote in message
<361d9047...@forums.borland.com>...