イベント(Delphi)
クラスとオブジェクト:インデックス への移動
このトピックで扱う内容は以下のとおりです。
- イベント プロパティとイベント ハンドラ
- 複数のイベント ハンドラの起動
イベントの概要
イベントは、システム内の出来事とその出来事に応答するコードをリンクするものです。その出来事が引き金となって、イベント ハンドラと呼ばれる手続きが実行されます。イベント ハンドラは、出来事に応じて必要なタスクを実行します。イベントを使用すれば、コンポーネントの動作を設計時または実行時にカスタマイズすることができます。コンポーネントの動作を変更するには、イベント ハンドラを、目的の動作をするカスタム イベント ハンドラに置き換えます。
イベント プロパティとイベント ハンドラ
Delphi で記述されたコンポーネントでは、プロパティを使って、イベント発生時にどのイベント ハンドラが実行されるかを示します。慣例的に、イベント プロパティの名前は "On" で始まり、プロパティは read/write メソッドではなくフィールドで実装されます。プロパティに格納される値は、イベント ハンドラ手続きを指すメソッド ポインタです。
以下の例で、TObservedObject クラスには、TPingEvent 型の OnPing イベントが含まれています。イベント ハンドラの格納には、FOnPing フィールドが使用されます。この例で定義しているイベント ハンドラ TListener.Ping からは、'TListener has been pinged.'(TListener への Ping が行われました。)と出力されます。
program EventDemo;
{$APPTYPE CONSOLE}
type
{ 手続き型を定義する }
TPingEvent = procedure of object;
{ 監視対象オブジェクト }
TObservedObject = class
private
FPing: TPingEvent;
public
property OnPing: TPingEvent read FPing write FPing;
{ 登録されているイベントがあれば起動する }
procedure TriggerEvent();
end;
{ リスナ }
TListener = class
procedure Ping;
end;
procedure TObservedObject.TriggerEvent;
begin
{ リスナが存在する場合のみ登録済みのイベントを呼び出す }
if Assigned(FPing) then
FPing();
end;
procedure TListener.Ping;
begin
Writeln('TListener has been pinged.');
end;
var
ObservedObject: TObservedObject;
Listener: TListener;
begin
{ オブジェクト インスタンスを作成する }
ObservedObject := TObservedObject.Create();
Listener := TListener.Create();
{ イベント ハンドラを登録する }
ObservedObject.OnPing := Listener.Ping;
{ イベントを起動する }
ObservedObject.TriggerEvent();// 'TListener has been pinged.' と出力される
Readln; // 終了する前にコンソールを一時停止する
end.
複数のイベント ハンドラの起動
Delphi では、イベントに割り当てることができるイベント ハンドラは 1 つだけです。1 つのイベントに応答して複数のイベント ハンドラを実行する必要がある場合は、イベントに割り当てられたイベント ハンドラから他のイベント ハンドラを呼び出す必要があります。以下のコードで、TListenerSubclass という TListener のサブクラスには、Ping2 という独自のイベント ハンドラがあります。この例で、OnPing イベントに応答して TListener.Ping イベント ハンドラを起動するには、そのイベント ハンドラを Ping2 イベント ハンドラから明示的に呼び出す必要があります。
program EventDemo2;
{$APPTYPE CONSOLE}
type
{ 手続き型を定義する }
TPingEvent = procedure of object;
{ 監視対象オブジェクト }
TObservedObject = class
private
FPing: TPingEvent;
public
property OnPing: TPingEvent read FPing write FPing;
{ 登録されているイベントがあれば起動する }
procedure TriggerEvent();
end;
{ リスナ }
TListener = class
procedure Ping;
end;
{ リスナのサブクラス }
TListenerSubclass = class(TListener)
procedure Ping2;
end;
procedure TObservedObject.TriggerEvent;
begin
{ リスナが存在する場合のみ登録済みのイベントを呼び出す }
if Assigned(FPing) then
FPing();
end;
procedure TListener.Ping;
begin
Writeln('TListener has been pinged.');
end;
procedure TListenerSubclass.Ping2;
begin
{ 基底クラスの Ping を呼び出す }
Self.Ping();
Writeln('TListenerSubclass has been pinged.');
end;
var
ObservedObject: TObservedObject;
Listener: TListenerSubclass;
begin
{ オブジェクト インスタンスを作成する }
ObservedObject := TObservedObject.Create();
Listener := TListenerSubclass.Create();
{ イベント ハンドラを登録する }
ObservedObject.OnPing := Listener.Ping2;
{ イベントを起動する }
ObservedObject.TriggerEvent();// 'TListener has been pinged.' に続いて
// 'TListenerSubclass has been pinged.' と出力される
Readln; // 終了する前にコンソールを一時停止する
end.