イベントの使い方
Win32のイベントAPIを使うと、異なるスレッドやプロセスにシグナルを送ってイベントを知らせることができます。Delphiでは、このイベントがTEventとしてカプセル化されて簡単に利用できます。
イベントの作成
コンストラクタをつぎのように呼び出して作成します。最初の引数はセキュリティ属性なので、Windows95ではnilでかまいません。2番目と3番目の引数は、作成するアプリケーションの仕様によります。
event1 := TEvent.Create(nil, True, False, 'StartEvent');
シグナルの送り方
シグナルはSetEventメソッドで送ります。受け側はWaitForメソッドで待ち受けます。コンストラクタでマニュアルリセットを指定したときは、ResetEventを実行する必要があります。
例
この例はスレッドにシグナルを送り、スレッドがカウンタをインクリメントするのを制御する例です。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, Unit2, StdCtrls, SyncObjs, ExtCtrls;
type
TForm1 = class(TForm)
cmdSet: TButton;
cmdReset: TButton;
txtCount: TEdit;
Timer1: TTimer;
cmdCountClear: TButton;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Timer1Timer(Sender: TObject);
procedure cmdSetClick(Sender: TObject);
procedure cmdResetClick(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure cmdCountClearClick(Sender: TObject);
private
{ Private 宣言 }
event1, event2: TEvent;
thread: TMyThread;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
count: Longint;
implementation
{$R *.DFM}
{ フォームが作成されたとき }
procedure TForm1.FormCreate(Sender: TObject);
begin
count := 0;
event1 := TEvent.Create(nil, True, False, 'StartEvent'); // イベントオブジェクト作成
event2 := TEvent.Create(nil, True, False, 'StopEvent'); // イベントオブジェクト作成
thread := TMyThread.Create(False); // スレッド作成
end;
{ フォームを閉じるとき }
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
thread.Destroy;
end;
{ スレッドがカウンタを更新することを確認するため }
procedure TForm1.Timer1Timer(Sender: TObject);
begin
txtCount.Text := IntToStr(count);
end;
{ スレッドがカウントするのを許可 }
procedure TForm1.cmdSetClick(Sender: TObject);
begin
event1.SetEvent;
end;
{ スレッドがカウントするのを禁止 }
procedure TForm1.cmdResetClick(Sender: TObject);
begin
event2.SetEvent;
end;
{ 閉じようとしたとき }
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
thread.Terminate; // スレッドを終了させる
end;
{ カウンタクリア }
procedure TForm1.cmdCountClearClick(Sender: TObject);
begin
count := 0;
end;
end.
{ スレッド側 }
unit Unit2;
interface
uses
Classes, Forms, Windows, SyncObjs;
type
TMyThread = class(TThread)
private
{ Private 宣言 }
event1, event2: TEvent;
enabled: Boolean; // カウントイネーブル
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean);
end;
implementation
{注意: VCL のメソッド/関数/プロパティを扱うには、以下のように
Synchronize メソッドの引数として渡したメソッドの中から扱う必要があります。
Synchronize(UpdateCaption);
UpdateCaption の中では以下のように VCL を呼び出すことができます。
procedure TMyThread.UpdateCaption;
begin
Form1.Caption := 'スレッドから書き換えました';
end; }
{ TMyThread }
uses Unit1;
{ スレッドが作成されたとき }
constructor TMyThread.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
event1 := TEvent.Create(nil, True, False, 'StartEvent');
event2 := TEvent.Create(nil, True, False, 'StopEvent');
enabled := False;
end;
{ Unit1のcountをインクリメントするワーキングスレッド }
procedure TMyThread.Execute;
var
r: TWaitResult;
begin
{ スレッドとして実行したいコードをここに記述 }
while True do
begin
if Terminated then
Exit;
r := event1.WaitFor(10); // 開始信号があるか
if r = wrSignaled then
begin
enabled := True;
event1.ResetEvent;
end;
r := event2.WaitFor(10); // 停止信号があるか
if r = wrSignaled then
begin
enabled := False;
event2.ResetEvent;
end;
if enabled then // enabledフラグがTrueならカウント
Inc(count);
Application.ProcessMessages;
end;
end;
end.