Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi: How to assign dynamically an event handler without overwriting the existing event handler?

I need to loop through Components and assign an event handler (for example Dynamically assigning OnClick event for all TButton to

ShowMessage('You clicked on ' + (Sender as TButton).Name);

The problem is that in some cases I already assigned the TButton OnClick event.

Is there a way to solve the problem?

Let's imagine I have Button1 for which the harcoded onclick event handler is:

ShowMessage('This is Button1');

After my "parsing" I would like that the full event handler for Button1 becomes:

ShowMessage('This is Button1'); // design time event handler code
ShowMessage('You clicked on ' + (Sender as TButton).Name); // runtime added

Note: I am looking for a soliution that allows me to use TButton as it is without inheriting from it.

like image 610
LaBracca Avatar asked Dec 21 '10 16:12

LaBracca


3 Answers

you could look for an assignment of OnClick before overwriting it, persist this and use it in your new handler - basically chaining the events.

Something like this:

  var original : TNotifyEvent;

  original := Component.OnClick;
  Component.OnClick := NewMethod;

and then in your NewMethod:

  if assigned(original) then original(Sender);

you'll likely not want a single original variable but instead hold a collection keyed on the component.

like image 116
John Pickup Avatar answered Nov 12 '22 23:11

John Pickup


If you are writing the replacement handlers yourself you could do the following:

  • Before assignment of the new handler, store a reference to the object and a reference to the original handler in a list or other structure.

  • In your replacement handler, included code to check the list to see if the current object has an entry. If it does, call the stored method before doing your own work.

This is fairly lightweight (a list where each entry is two pointers). With a little extra work (to support ordering) you could probably even chain more than one replaced handler.

like image 35
Larry Lustig Avatar answered Nov 12 '22 21:11

Larry Lustig


You can't do that directly as Delphi does not support chained events (I'm assuming VCL Delphi).

So anything that you want to do that involves directly assigning the OnClick event will not work. What you might do is create an interceptor component, that is, something with this signature:

type
   TButton = class(stdctrls.TButton)

You'll have to override the OnClick property so that the write event stores the event handler into an internal list, available to class.

property OnClick: TNotifyEvent read GetOnClick write SetOnClick;

then on the SetOnClick handler you'll be able to just store your event handler in the internal list.

Now, you will have to override the Click procedure so that it invokes every delegate (every event handler) in turn.

procedure Click; override;

And that will do it.

Note that after all you'll be kind of subclassing the TButton class, even if you're using the same name... Anyway that's the best solution I can think of. The cool thing about this is that you can still use assignments without having to know about chained events, you can just do:

MyButton.OnClick := MyHandler

and it will get automatically chained with the rest of event handlers.

like image 31
Jorge Córdoba Avatar answered Nov 12 '22 23:11

Jorge Córdoba