まずSpring4Dのなかでマルチキャストを実現しているのはEvent<T>レコード型になります。これを使用するのに必要なユニットですが、Source\Baseフォルダにある
- Spring.pas
- Spring.inc
- Spring.ResourceStrings.pas
- Spring.Events.Base.pas
- Spring.Events.pas
- jedi.inc
では実際にEvent<T>でマルチキャストを試してみます。今回はメインフォームからモードレスなサブフォームをいくつか表示して、フォーム上のボタンクリックの発生と、その累計回数を各フォームに通知します。
まず通知のためのイベントと、イベントを登録/削除するインタフェースを定義します。
type TNotifyNumber = procedure (Sender: TObject; Number: Integer) of object; ISubject = interface procedure Add(AEvent: TNotifyNumber); procedure Remove(AEvent: TNotifyNumber); end;TNotifyNumberが通知のためのイベントハンドラの型、ISubjectがそのイベントハンドラを登録/削除する機能を持たせたインタフェースです。メインフォーム、サブフォームの両方で使用するので別ユニットで定義しておきます。次はメインフォームです。
uses Spring, ... type TForm1 = class(TForm,ISubject) ... procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private FEvent: Event<TNotifyNumber> public procedure Add(AEvent: TNotifyNumber); procedure Remove(AEvent: TNotifyNumber); end; procedure TForm1.FormCreate(Sender: TObject); begin FEvent := Event<TNotifyNumber>.Create; end; procedure TForm1.FormDestroy(Sender: TObject); begin FEvent.Clear; end; procedure TForm1.Add(AEvent: TNotifyNumber); begin FEvent.Add(AEvent); end; procedure TForm1.Remove(AEvent: TNotifyNumber); begin FEvent.Remove(AEvent); end;メインフォームはISubjectインタフェースを継承するようにして、AddとRemoveを実装します。Event<T>はレコード型ですが、内部の適切な初期化のためにclass function Createを呼び出しておく必要があります。AddとRemoveでは単にEvent<T>のAddとRemoveを呼び出すだけです。一方サブフォームでは
type TForm2 = class(TForm) ... private FSubject: ISubject; public property Subject: ISubject read FSubject write FSubject; end;メインフォームをISubjectとして保持するためのプロパティを用意します。これでメインフォームからサブフォームを生成、表示する処理は
procedure TForm1.Button1Click(Sender: TObject); begin with TForm2.Create(Self) do begin Subject := Self; Show; end; end;となります。サブフォーム側ではボタンクリックで任意にマルチキャストイベントを登録、削除できるようにしてみます、
type TForm2 = class(TForm) Button1: TButton; Button2: TButton; Label1: TLabel; procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private ... procedure DoNotifyNumber(Sender: TObject; Number: Integer); public ... end; procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin Subject.Remove(DoNotifyNumber); Action := caFree; end; procedure TForm2.Button1Click(Sender: TObject); begin Subject.Add(DoNotifyNumber); end; procedure TForm2.Button2Click(Sender: TObject); begin Subject.Remove(DoNotifyNumber); end; procedure TForm2.DoNotifyNumber(Sender: TObject; Number: Integer); begin Label1.Caption := 'Notified number is ' + IntToStr(Number); end;procedure DoNotifyNumberがマルチキャストイベントのイベントハンドラで、これをButton1/Button2のクリックイベントでSubjectにAdd/Removeすることで登録、削除します。最後にメインフォーム側からのマルチキャストイベントの呼び出しです。
type TForm1 = class(TForm,ISubject) ... Label1: TLabel; Button2: TButton; procedure Button2Click(Sender: TObject); private FCount: Integer; ... public ... end; procedure TForm1.Button2Click(Sender: TObject); begin FCount := FCount + 1; Label1.Caption := IntToSTr(FCount); FEvent.Invoke(Self,FCount); end;Selfと1ずつ増える整数値(FCount)でEvent<T>のInvokeメソッドを呼び出すだけです(正確にはInvokeはイベントハンドラ型(<T> = <TNotifyNumber>)のプロパティで、Invoke(...)とすることでメソッドの呼び出しになる)。
Spring4DのEventがよくできていることもあってそれほど難しくはないと思います(気をつけなければならないのはclass function CreateによるEvent<T>の明示的な初期化くらい)。ただEvent<T>のTには通常のイベントハンドラ(procedure ... of object)だけでなく、無名メソッド(reference to ...)も入れられるのですが、この場合Event<T>で保持されるものが自動的に生成される無名メソッド値(TInterfacedObjectの派生クラスのインスタンス)であり、そのポインタをAddの呼び出し側(TForm2)では知ることができないためRemoveできない、という点には注意が必要です。
0 件のコメント:
コメントを投稿