When you develop (Win32) applications using Delphi you almost always write the code to handle some component's event(s). For example, when you drop a TButton on a form and double click it, an empty event handler is created where you write the code to react on the user click action.
Win32 Delphi allows you to assign only one method as a handler to an event of a component.
With Delphi for .NET a notion of multicast events was introduced. A developer can assign two or more methods to be called when an event gets fired.
Let's see how to build a Win32 Delphi object that maintains a list of the methods its event(s) is handled by - thus creating a simulation of multicast event handling.
Before we start, I strongly suggest that you freshen up your Delphi OOP and custom component development memory...
A simple example of multicast event handling in Win32 Delphi
First, we'll define a simple class (TMultiEventClass) with only one event of TMutliEvent type. In order to store a list of methods that will be called when event is fired (using the FireMultiEvent) we'll use a fMultiEventHandlers TList object. The TList Delphi class is designed to be used as a storage mechanism for an array of pointers.
By design, each method (function or procedure) in Delphi code can be represented with a TMethod Delphi type. A TMethod type can be used, for example, to execute a method by its name.
type
PMethod = ^TMethod;
TMutliEvent = procedure(const Value : string) of object;
TMultiEventClass = class
private
fMultiEventHandlers : TList;
public
constructor Create;
destructor Destroy; override;
procedure AddMultiEvent(const Value: TMutliEvent);
procedure RemoveMultiEvent(const Value: TMutliEvent);
procedure FireMultiEvent;
end;
|
The above code is the interface part of the TMultiEventClass class. The fMultiEventHandlers is a private list used to store pointers to methods that will handle an event of type TMutliEvent.
Since this class allows multiple event handler to be assigned to one event we also need two procedures to add an event handler and to remove an event handler: AddMultiEvent and RemoveMultiEvent.
Here's the implementation part:
{ TMultiEventClass }
//create the event handlers storage
constructor TMultiEventClass.Create;
begin
inherited Create;
fMultiEventHandlers := TList.Create;
end;
//clean up
destructor TMultiEventClass.Destroy;
var
cnt: Integer;
begin
for cnt := 0 to -1 + fMultiEventHandlers.Count do
Dispose(fMultiEventHandlers[cnt]);
fMultiEventHandlers.Free;
inherited;
end;
//add an event handler to the list
procedure TMultiEventClass.AddMultiEvent(
const Value: TMutliEvent);
var
h: PMethod;
begin
h := New(PMethod);
h^.Code := TMethod(Value).Code;
h^.Data := TMethod(Value).Data;
fMultiEventHandlers.Add(h);
end;
//remove an event handler from the list (if there)
procedure TMultiEventClass.RemoveMultiEvent(
const Value: TMutliEvent);
var
cnt: Integer;
begin
for cnt := 0 to -1 + fMultiEventHandlers.Count do
begin
if (TMethod(Value).Code =
TMethod(fMultiEventHandlers[cnt]^).Code) and
(TMethod(Value).Data =
TMethod(fMultiEventHandlers[cnt]^).Data) then
begins
Dispose(fMultiEventHandlers[cnt]);
fMultiEventHandlers.Delete(cnt);
Break;
end;
end;
end;
//"fire" event (call all handlers)
procedure TMultiEventClass.FireMultiEvent;
var
cnt: Integer;
msg : string;
begin
for cnt := 0 to -1 + fMultiEventHandlers.Count do
begin
msg := Format('%d/%d %s',
[1 + cnt,
fMultiEventHandlers.Count,
'fired!']);
TMutliEvent(fMultiEventHandlers[cnt]^)(msg);
end;
end;
|
In the above code, the FireMultiEvent procedure is used to fake raising an event (with more event handlers). In normal scenarios this would be a private method initiated by an action inside the
TMultiEventClass's code.
For a better understanding of the code, we'll use a simple test example. Drop a TButton on a Delphi form, and assign the next code for the OnClick event:
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
test : TMultiEventClass;
begin
test := TMultiEventClass.Create;
try
test.AddMultiEvent(Handler1);
test.AddMultiEvent(Handler2);
test.RemoveMultiEvent(Handler1);
test.AddMultiEvent(Handler3);
test.FireMultiEvent;
finally
test.Free;
end;
end;
|
A test object is created, AddMultiEvent is used to store a reference to 2 methods Handler1 and Handler2, Handler1 is then removed using the RemoveMultiEvent procedure, one additional method is added to the event handler list: Handler3, and finally FireMultiEvent procedure is called.
The three Handler1, Handler2 and Handler3 methods are defined as:
procedure TForm1.Handler1(const value: string);
begin
ShowMessage('h1: ' + value);
end;
procedure TForm1.Handler2(const value: string);
begin
ShowMessage('h2: ' + value);
end;
procedure TForm1.Handler3(const value: string);
begin
ShowMessage('h3: ' + value);
end;
|
What will happen when you run this code? What methods will be called by FireMultiEvent? "Handler2" and "handler3" is the answer!

That's it. Multicast events in Win32 Delphi! If you do not believe me, download the code and see for yourself.
Questions, comments? You already know: Delphi Programming Forum!
Note: Looking for "Simulating class properties in (Win32) Delphi"?