Asynchronous Calls/ja
│
English (en) │
français (fr) │
日本語 (ja) │
русский (ru) │
問題について
あるイベントを処理する必要があっても、その場ですぐには処理を実行できない場合があります。例えば、オブジェクトを free しなければいけないのに、後ほど親オブジェクトなどからそのオブジェクトを参照される可能性がある場合です。
解決方法
Application.QueueAsyncCall メソッドを使用してください。
TDataEvent = procedure (Data: PtrInt) of object; procedure QueueAsyncCall(AMethod: TDataEvent; Data: PtrInt);
これは、任意のメソッドを「キュー」(待ち行列)に入れ、主イベントループ(訳注 : ユーザプログラムの中にあって、ウィンドウシステムから送られてくるイベントを処理するループ。Lazarus等 では隠蔽されている)の中で、他のイベントの処理が全て終わった後で実行するようにします。その際、メソッドに任意のパラメタを渡すことができます。上の例では、free する時点では親の実行が終了していますから、free しようとしているオブジェクトへの参照は消滅しており、安全に free することができるわけです。
これは ReleaseComponent の、よりジェネリックなヴァージョンであり、ReleaseComponent もこのメソッドを呼んでいることにご注意ください。
例
次のプログラムは QueueAsyncCall の使い方を示しています。 CallButton を押すと、'Click 1', 'Click 2' そして 'Async 1' が LogListBox に追加されます。注目すべきところは、Async メソッドは、CallButtonClick イベントが終了した後に実行される、という点です。
unit TestQueueAsyncCall; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Buttons, StdCtrls; type { TQueueAsyncCallForm } TQueueAsyncCallForm = class(TForm) CallButton: TButton; LogListBox: TListBox; procedure CallButtonClick(Sender: TObject); private { private declarations } FCounter: PtrInt; procedure Async(Data: PtrInt); public { public declarations } end; var QueueAsyncCallForm: TQueueAsyncCallForm; implementation { TQueueAsyncCallForm } procedure TQueueAsyncCallForm.CallButtonClick(Sender: TObject); begin LogListBox.Items.Add('Click 1'); FCounter := FCounter+1; Application.QueueAsyncCall(@Async,FCounter); LogListBox.Items.Add('Click 2'); end; procedure TQueueAsyncCallForm.Async(Data: PtrInt); begin LogListBox.Items.Add('Async '+ IntToStr(Data)); end; initialization {$I testqueueasynccall.lrs} end.