RAD Studio (Common)
ContentsIndex
PreviousUpNext
Events

This topic describes the following material:

  • Event properties and event handlers
  • Triggering multiple event handlers

An event links an occurrence in the system with the code that responds to that occurrence. The occurrence triggers the execution of a procedure called an event handler. The event handler performs the tasks that are required in response to the occurrence. Events allow the behavior of a component to be customized at design-time or at runtime. To change the behavior of the component, replace the event handler with a custom event handler that will have the desired behavior.

Components that are written in Delphi use properties to indicate the event handler that will be executed when the event occurs. By convention, the name of an event property begins with "On", and the property is implemented with a field rather than read/write methods. The value stored by the property is a method pointer, pointing to the event handler procedure. 

In the following example, the TObservedObject class includes an OnPing event, of type TPingEvent. The FOnPing field is used to store the event handler. The event handler in this example, TListener.Ping, prints 'TListener has been pinged!'.

program EventDemo;

{$APPTYPE CONSOLE}
type
  { Define a procedural type }
  TPingEvent = procedure of object;

  { The observed object }
  TObservedObject = class
  private
    FPing: TPingEvent;

  public
    property OnPing: TPingEvent read FPing write FPing;

    { Triggers the event if anything is registered }
    procedure TriggerEvent();
  end;

  { The listener }
  TListener = class
    procedure Ping;
  end;


procedure TObservedObject.TriggerEvent;
begin
  { Call the registerd event only if there is a listener }
  if Assigned(FPing) then
    FPing();
end;

procedure TListener.Ping;
begin
  WriteLn('TListener has been pinged.');
end;

var
  ObservedObject: TObservedObject;
  Listener: TListener;

begin
  { Create object instances }
  ObservedObject := TObservedObject.Create();
  Listener := TListener.Create();

  { Register the event handler }
  ObservedObject.OnPing := Listener.Ping;

  { Trigger the event }
  ObservedObject.TriggerEvent(); // Should output 'TListener has been pinged.'
  ReadLn;                        // Pause console before closing
end.

In Delphi for Win32, events can be assigned only a single event handler. If multiple event handlers must be executed in response to an event, the event handler assigned to the event must call any other event handlers. In the following code, a subclass of TListener called TListenerSubclass has its own event handler called Ping2. In this example, the Ping2 event handler must explicitly call the TListener.Ping event handler in order to trigger it in response to the OnPing event.

program EventDemo2;

{$APPTYPE CONSOLE}

type
  { Define a procedural type }
  TPingEvent = procedure of object;

  { The observed object }
  TObservedObject = class
  private
    FPing: TPingEvent;

  public
    property OnPing: TPingEvent read FPing write FPing;

    { Triggers the event if anything is registered }
    procedure TriggerEvent();
  end;

  { The listener }
  TListener = class
    procedure Ping;
  end;

  { The listener sub-class }
  TListenerSubclass = class(TListener)
    procedure Ping2;
  end;

procedure TObservedObject.TriggerEvent;
begin
  { Call the registerd event only if there is a listener }
  if Assigned(FPing) then
    FPing();
end;

procedure TListener.Ping;
begin
  WriteLn('TListener has been pinged.');
end;

procedure TListenerSubclass.Ping2;
begin
  { Call the base class ping }
  Self.Ping();
  WriteLn('TListenerSubclass has been pinged.');
end;

var
  ObservedObject: TObservedObject;
  Listener: TListenerSubclass;

begin
  { Create object instances }
  ObservedObject := TObservedObject.Create();
  Listener := TListenerSubclass.Create();

  { Register the event handler }
  ObservedObject.OnPing := Listener.Ping2;

  { Trigger the event }
  ObservedObject.TriggerEvent(); // Should output 'TListener has been pinged.'
                                 // and then 'TListenerSubclass has been pinged.'
  ReadLn;                        // Pause console before closing
end.
Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
What do you think about this topic? Send feedback!