CreateAnonymousThread の使い方

 Delphi のXE から、CreateAnonymousThread が使用できる様になりました。
スレッドとして、BeginThreadより、使い易く、SynchronizeやTerminate、OnTerminate が使用できます。
優先順位 Priority も指定できるので、通常のスレッドとほとんど同じ動作が可能です。

サンプルプログラムとして、タイマールーチンを作成してみました。
スレッドサンプル

 プログラムを作成する場合は、スレッドの実行中に、プログラムを閉じられないようにする必要があります。
その方法は、メカコントロール(測定用)プログラム作成時の注意点に詳しく記されているので、そちらを参照してください。

メインスレッドのプロシージャ、オブジェクトの実行は、実行スレッドプログラム内に、メソッドを定義して行います。

サンプルプログラム TimerTest0

unit Timertest;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Samples.Spin, Vcl.ExtCtrls, System.Diagnostics;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    SpinEdit1: TSpinEdit;
    Label1: TLabel;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private 宣言 }
    procedure TimerThreadProc;
  public
    { Public 宣言 }
    flgStop : Boolean;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


//=============================================================================
// スレッド処理用メソッド
// TStopWatchの使用には,usesにDiagnosticsが必要です
// Stringを使用してもメモリーリークは発生しません
//=============================================================================
procedure TForm1.TimerThreadProc;
var
  AStopWatch : TStopWatch;
  FTimeValue : Int64;
  FTimeDis   : Int64;
  Amin       : Integer;
  Asec       : Integer;
  FSync      : TThreadProcedure;
  FSyncEnd   : TThreadProcedure;
begin
  // メソッドの定義
  FSync := procedure
  begin
    Label1.Caption := Format('残%4d分%2d秒', [Amin, Asec]);
    Label1.Update;
  end;

  FSyncEnd := procedure
  begin
    Button1.Enabled := True;
    Button3.Enabled := True;
    Winapi.Windows.Beep(700, 1000);
  end;

  //--------------- これより下が本体コード -----------------
  AStopWatch := TStopwatch.StartNew;
  FTimeValue := SpinEdit1.Value;
  FTimeDis := FTimeValue;
  while not flgStop and (FTimeDis > 0) do begin
    // FTimeDisの値は秒
    FTimeDis := FTimeValue - AStopWatch.ElapsedMilliseconds div 1000;
    Amin     := FTimeDis div 60;
    Asec     := FTimeDis mod 60;

    TThread.Synchronize(TThread.CurrentThread, FSync);

    // これがないとCPU使用率が跳ね上がります
    TThread.Sleep(1);
  end;

  // 上の処理が終了したら
  TThread.Synchronize(TThread.CurrentThread, FSyncEnd);
end;

//=============================================================================
// CreateAnonymousThreadでスレッドを作成して実行します
// タイマーの起動や時間経過の監視はスレッドで行います
// CreateAnonymousThreadはデフォルトでFreeOnTerminate True で
// スレッド終了時自動的に開放されます
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1.Enabled := False;
  Button3.Enabled := False;
  flgStop := False;
  TThread.CreateAnonymousThread(TimerThreadProc).Start;
end;

//=============================================================================
//  タイマーストップ
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  flgStop := True;
end;

//==============================================================
// フォームのクローズボタンは非表示又はグレイアウトしてください
// スレッドの実行中プログラムを終了しないようにします
//==============================================================
procedure TForm1.Button3Click(Sender: TObject);
begin
  Close;
end;

end.

次の例は、スレッドの終了を、他のスレッドで待ち合わせて、スレッド終了後の処理をする例です。
OnTerminateを使用すれば、簡単なのですが、一つの例として取り上げました。
タイマーを開始し、終了する前に、再度タイマーをスタートすると、タイマーはリスタートします。

サンプルプログラム TimerTest1

unit TimerTest;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Samples.Spin, Vcl.ExtCtrls, System.Diagnostics;

type
  TForm1 = class(TForm)
    Button1: TButton;
    SpinEdit1: TSpinEdit;
    Button2: TButton;
    Label1: TLabel;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    flgStop : Boolean;
    TimerThread : TThread;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=====================================================================
// TimerThreadの終了を待ちます
// FreeOnTerminate := Trueの場合は
//              TimerThread = Nil
// FreeOnTerminate := Falseの場合は  (指定の無い場合はデフォルトでTrue)
//              TimerThread.Terminate
//              FreeAndNil(TimerThread)
// OnTerminatを使用した方が簡単です。
//=====================================================================
procedure WaitThread(TH: pointer);
begin
  WaitForSingleObject(integer(TH^), INFINITE);
  with Form1 do begin
    if Assigned(TimerThread) then begin
      flgStop := True;
      TimerThread.Terminate;
      FreeAndNil(TimerThread);
    end;
    Button3.Enabled := True;
  end;
  // WaitThreadスレッド終了
  EndThread(0);
end;

//==================================================================================
// CreateAnonymousThreadでスレッドを作成して実行
// タイマーの起動や時間経過の監視はスレッドで行います
// TStopWatchの使用には,usesにDiagnosticsが必要です
// Button1.Enabled := False をコメントアウトして次の { } 内を有効にすれば
// タイマー動作の途中で Button1をクリックすれ事によりタイマーのリスタートが出来ます。
// (FreeOnTerminate := False の必要があります)
//==================================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  AStopWatch : TStopWatch;
  FTimeValue : Int64;
  FTimeDis   : Int64;
  Amin       : Integer;
  dmp        : Int64;
  Asec       : Integer;
  msec       : Integer;
  id         : Cardinal;
begin
  if Assigned(TimerThread) then begin
    flgStop := True;
    TimerThread.Terminate;
    FreeAndNil(TimerThread);
  end;

  flgStop := False;
  // タイマースレッドの生成
  TimerThread := TThread.CreateAnonymousThread(
    procedure
    begin
      AStopWatch := TStopwatch.StartNew;
      FTimeValue := SpinEdit1.Value;

      while true do begin
        // FTimeDisの値は秒
        FTimeDis := FTimeValue * 1000 - AStopWatch.ElapsedMilliseconds;
        dmp      := FTimeDis mod 60000;
        Amin     := FTimeDis div 60000;
        Asec     := dmp div 1000;
        msec     :=(dmp mod 1000) div 100 * 100;
        TThread.Synchronize(TimerThread,
          procedure
          begin
            Label1.Caption := Format('残%4d分%2d秒%3d㍉秒', [Amin, Asec, msec]);
            Label1.Update;
          end
        );

        if flgStop       then break;
        if FTimeDis <= 0 then break;

        // これがないとCPU使用率が跳ね上がります
        Sleep(10);
      end;
      // 無くてもOK
      AStopWatch.Stop;
      // 上のループ処理が終了したらビープ音
      TThread.Synchronize(TimerThread,
        procedure
        begin
          Winapi.Windows.Beep(500, 1000);
        end
      );
    end
  );
  if Assigned(TimerThread) then begin
    Button3.Enabled := False;
    // スレッド優先順位
    TimerThread.Priority := tpNormal;
    // TimerThreadが終了してもスレッド開放しない指定
    // 指定をしない場合は 自動的にスレッド開放 デフォルトは True
    TimerThread.FreeOnTerminate := False;
    TimerThread.Start;
    // TimerThreadの終了を監視するスレッドの生成
    CloseHandle(BeginThread(nil, 0, addr(WaitThread), addr(TimerThread.Handle), 0, Id));
  end;
end;

//=============================================================================
//  タイマーストップ
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  flgStop := True;
end;

//==============================================================
// フォームのクローズボタンは非表示又はグレイアウトしてください
// スレッドの実行中プログラムを終了しないようにします
//==============================================================
procedure TForm1.Button3Click(Sender: TObject);
begin
  Close;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Label1.Caption := Format('残%4d分%2d秒%3d㍉秒', [0, 0, 0]);
end;

end.

  メソッドの定義で、実行部分をメインスレッドに置いた場合の例です。
  public
    { Public宣言 }
    TimerThread : TThread;
 の宣言をして
   TimerThread := TThread.CreateAnonymousThread(); 
  の関連付けをして、いない為、スレッドの終了に Terminate、OnTerminate 等の使用は出来ません。

サンプル TimerTest2

unit Timertest;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Samples.Spin, Vcl.ExtCtrls, System.Diagnostics;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    SpinEdit1: TSpinEdit;
    Label1: TLabel;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private 宣言 }
    procedure TimerThreadProc;
    procedure Timedisp(Amin, Asec: integer);
    procedure Enddisp(Tone, Time: integer);

  public
    { Public 宣言 }
    flgStop : Boolean;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================
// スレッドの補助ルーチン
//=============================
procedure TForm1.Timedisp(Amin, Asec: integer);
begin
  Label1.Caption := Format('残%4d分%2d秒', [Amin, Asec]);
  Label1.Update;
end;

procedure TForm1.Enddisp(Tone, Time: integer);
begin
  Button1.Enabled := True;
  Button3.Enabled := True;
  Winapi.Windows.Beep(Tone, Time);
end;


//=============================================================================
// スレッド処理用メソッド
// TStopWatchの使用には,usesにDiagnosticsが必要です
// Stringを使用してもメモリーリークは発生しません
//=============================================================================
procedure TForm1.TimerThreadProc;
var
  AStopWatch : TStopWatch;
  FTimeValue : Int64;
  FTimeDis   : Int64;
  Amin       : Integer;
  Asec       : Integer;
  FSync      : TThreadProcedure;
  FSyncEnd   : TThreadProcedure;
begin
  // メソッドの定義
  FSync := procedure
  begin
    // スレッド外のプロシージャ実行
    Timedisp(Amin, Asec);
  end;

  FSyncEnd := procedure
  begin
    // スレッド外のプロシージャ実行
    Enddisp(700, 1000);
  end;

  //--------------- これより下が本体コード -----------------
  AStopWatch := TStopwatch.StartNew;
  FTimeValue := SpinEdit1.Value;
  FTimeDis := FTimeValue;
  while not flgStop and (FTimeDis > 0) do begin
    // FTimeDisの値は秒
    FTimeDis := FTimeValue - AStopWatch.ElapsedMilliseconds div 1000;
    Amin     := FTimeDis div 60;
    Asec     := FTimeDis mod 60;

    TThread.Synchronize(TThread.CurrentThread, FSync);

    // これがないとCPU使用率が跳ね上がります
    TThread.Sleep(1);
  end;

  // 上の処理が終了したら
  TThread.Synchronize(TThread.CurrentThread, FSyncEnd);
end;

//=============================================================================
// CreateAnonymousThreadでスレッドを作成して実行します
// タイマーの起動や時間経過の監視はスレッドで行います
// CreateAnonymousThreadはデフォルトでFreeOnTerminate True で
// スレッド終了時自動的に開放されます
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1.Enabled := False;
  Button3.Enabled := False;
  flgStop := False;
  TThread.CreateAnonymousThread(TimerThreadProc).Start;
end;

//=============================================================================
//  タイマーストップ
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  flgStop := True;
end;

//==============================================================
// フォームのクローズボタンは非表示又はグレイアウトしてください
// スレッドの実行中プログラムを終了しないようにします
//==============================================================
procedure TForm1.Button3Click(Sender: TObject);
begin
  Close;
end;

end.

  次の例は Terminate CheckTerminated を使用して、スレッドを途中停止させる例です。

 サンプル TimerTest3

unit Timertest;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Samples.Spin, Vcl.ExtCtrls, System.Diagnostics;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    SpinEdit1: TSpinEdit;
    Label1: TLabel;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private 宣言 }
    procedure TimerThreadProc;
    procedure Enddisp(Tone, Time:integer);

  public
    { Public 宣言 }
    TimerThread : TThread;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// スレッドの補助ルーチン
procedure TForm1.Enddisp(Tone, Time: integer);
begin
  Button1.Enabled := True;
  Button3.Enabled := True;
  Winapi.Windows.Beep(Tone, Time);
end;

//=============================================================================
// スレッド処理用メソッド
// TStopWatchの使用には,usesにDiagnosticsが必要です
// Stringを使用してもメモリーリークは発生しません
//=============================================================================
procedure TForm1.TimerThreadProc;
var
  AStopWatch : TStopWatch;
  FTimeValue : Int64;
  FTimeDis   : Int64;
  Amin       : Integer;
  Asec       : Integer;
  FSync      : TThreadProcedure;
  FSyncEnd   : TThreadProcedure;
begin
  // スレッド外のプロシージャ呼び出しメソッドの定義
  FSync := procedure
  begin
    Label1.Caption := Format('残%4d分%2d秒', [Amin, Asec]);
    Label1.Update;
  end;

  FSyncEnd := procedure
  begin
    Enddisp(700, 1000);
  end;

  //--------------- これより下が本体コード -----------------
  AStopWatch := TStopwatch.StartNew;
  FTimeValue := SpinEdit1.Value;
  while not TimerThread.CheckTerminated do begin
    // FTimeDisの値は秒
    FTimeDis := FTimeValue - AStopWatch.ElapsedMilliseconds div 1000;
    Amin     := FTimeDis div 60;
    Asec     := FTimeDis mod 60;

    TThread.Synchronize(TThread.CurrentThread, FSync);
    if FTimeDis <= 0 then TimerThread.Terminate;

    // これがないとCPU使用率が跳ね上がります
    TThread.Sleep(1);
  end;

  // 上の処理が終了したら
  TThread.Synchronize(TThread.CurrentThread, FSyncEnd);
end;

//=============================================================================
// CreateAnonymousThreadでスレッドを作成して実行します
// タイマーの起動や時間経過の監視はスレッドで行います
// CreateAnonymousThreadはデフォルトで FreeOnTerminate True です
// スレッド終了時自動的に開放されます
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1.Enabled := False;
  Button3.Enabled := False;
  TimerThread := TThread.CreateAnonymousThread(TimerThreadProc);
  TimerThread.Start;
end;

//=============================================================================
//  スレッドの停止
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  TimerThread.Terminate;
end;

//==============================================================
// フォームのクローズボタンは非表示又はグレイアウトしてください
// スレッドの実行中プログラムを終了しないようにします
//==============================================================
procedure TForm1.Button3Click(Sender: TObject);
begin
  Close;
end;

end.

 OnTerminate Terminate CheckTerminated を使用したスレッドの例です。
OnTerminateを使用すれば、スレッドの終了を簡単に捉えることができます。

 サンプルプログラム TimerTest4

unit Timertest;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Samples.Spin, Vcl.ExtCtrls, System.Diagnostics;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    SpinEdit1: TSpinEdit;
    Label1: TLabel;
    Button3: TButton;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private 宣言 }
    procedure TimerThreadProc;
    procedure Enddisp(Tone, Time:integer);
    procedure MyThread1Terminate(Sender: TObject);
  public
    { Public 宣言 }
    TimerThread : TThread;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//==========================
// スレッドの補助ルーチン
//==========================
procedure TForm1.Enddisp(Tone, Time: integer);
begin
  Winapi.Windows.Beep(Tone, Time);
end;

//=============================================================================
// スレッドの終了割り込みイベント処理
// 指定したスレッドが終了するとイベントが発生しこのプロシージャが呼び出されます
//=============================================================================
procedure TForm1.MyThread1Terminate(Sender: TObject);
begin
  TimerThread := nil;
//  Button1.Enabled := True;
  Button3.Enabled := True;
  Label2.caption:='破棄しました';
end;

//=============================================================================
// スレッド処理用メソッド
// TStopWatchの使用には,usesにDiagnosticsが必要です
// Stringを使用してもメモリーリークは発生しません
//=============================================================================
procedure TForm1.TimerThreadProc;
var
  AStopWatch : TStopWatch;
  FTimeValue : Int64;
  FTimeDis   : Int64;
  Amin       : Integer;
  Asec       : Integer;
  FSync      : TThreadProcedure;
  FSyncEnd   : TThreadProcedure;
begin
  // メソッドの定義
  FSync := procedure
  begin
    Label1.Caption := Format('残%4d分%2d秒', [Amin, Asec]);
    Label1.Update;
  end;

  // スレッド外のプロシージャ呼び出しメソッドの定義
  FSyncEnd := procedure
  begin
    Enddisp(700, 1000);
  end;

  //--------------- これより下が本体コード -----------------
  AStopWatch := TStopwatch.StartNew;
  FTimeValue := SpinEdit1.Value;
  while not TimerThread.CheckTerminated do begin
    // FTimeDisの値は秒
    FTimeDis := FTimeValue - AStopWatch.ElapsedMilliseconds div 1000;
    Amin     := FTimeDis div 60;
    Asec     := FTimeDis mod 60;

    TThread.Synchronize(TThread.CurrentThread, FSync);
    if FTimeDis <= 0 then TimerThread.Terminate;
    // これがないとCPU使用率が跳ね上がります
    TThread.Sleep(1);
  end;

  // 上の処理が終了したら
  TThread.Synchronize(TThread.CurrentThread, FSyncEnd);
end;

//=============================================================================
// CreateAnonymousThreadでスレッドを作成して実行します
// タイマーの起動や時間経過の監視はスレッドで行います
// CreateAnonymousThreadはデフォルトで FreeOnTerminate True です
// スレッド終了時自動的に開放されます
// スレッド終了時にスレッドを解放したくない場合は
// FreeOnTerminate := False;  が必要です。
// OnTerminateの指定をします
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  // スレッドが生成されていたら終了
  if TimerThread <> nil then exit;
//  Button1.Enabled := False;
  Button3.Enabled := False;
  TimerThread := TThread.CreateAnonymousThread(TimerThreadProc);
  TimerThread.OnTerminate := MyThread1Terminate;
  TimerThread.Start;
  Label2.caption:='スタートしました。';
end;

//=============================================================================
//  スレッドの停止
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  if TimerThread <> nil then TimerThread.Terminate;
end;

//==============================================================
// フォームのクローズボタンは非表示又はグレイアウトしてください
// スレッドの実行中プログラムを終了しないようにします
//==============================================================
procedure TForm1.Button3Click(Sender: TObject);
begin
  Close;
end;

end.


タイマーサンプル


  CreateAnonymousThreadとは関係ないのですが、 TNotifyEvent を使用したタイマーの使用例があったので、検討してみました。
元のSourceのままだと、若干問題があるので修正しました。
タイマー割り込みので、VCL(表示)の変更をした後、タイマー自身を開放しているので、VCL(表示)の条件により、表示が正しく更新される以前に、タイマーが失われ、エラーになる可能性があります。
Synchronize が使用できないので、PostMessage を使用して、同期が取れるようにしてみました。
備忘録として、ここに載せておきます。

unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

const
  TH_MESSAGE = WM_APP + 1;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
    procedure WindowsProcd(var Msg: Tmessage); message TH_MESSAGE;     // メッセージ WM_APP + 1 処理
    procedure PostLabelText(LB: TLabel; Text: string; DispTime: Integer);
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;


implementation

{$R *.dfm}

//=========================================================
// SendMessage又はPostMessage送信先
// WParamの値は1しか使用していませんが 参考として Case 文
// 使用しています。
//=========================================================
procedure TForm1.WindowsProcd(var Msg: Tmessage);
begin
  case Msg.WParam of
    1: begin
          Label1.Caption := 'タイマー終了';
          Button2.Enabled := True;
          Button1.Enabled := True;
       end;
  end;
end;

//========================================================================
// タイマーを生成してイベントもプロシージャ内で処理をしています。
// タイマーイベント内で、タイマー自身の開放をしているので注意が必要です。
// Vclと同期をとる為 PostMessage を使用しています。
// 普通に TTimerを使用したほうが簡単だし、問題もありません
//========================================================================
procedure TForm1.PostLabelText(LB: TLabel; Text: string; DispTime: Integer);
type
  TNotifyEventProc = reference to procedure(Sender: TObject);
var
  Timer: TTimer;
  {MakeNotifyEventHandler begin}
  function MakeNotifyEventHandler(const Proc: TNotifyEventProc): TNotifyEvent;
  var
    method: TMethod;
  begin
    method.Data := PPointer(@Proc)^;
    method.Code := PPointer(PByte(PPointer(PPointer(@Proc)^)^)+$C)^;
    Result := TNotifyEvent(method);
  end;
  {MakeNotifyEventHandler end}
begin
  LB.Caption  := Text;
  Timer := TTimer.Create(nil);
  Timer.Enabled := False;
  Timer.OnTimer := MakeNotifyEventHandler
                   (
                     procedure (Sender: TObject)
                     begin
                        PostMessage(Form1.Handle, TH_MESSAGE, 1, 0);
                        Timer.Free;
                     end
                   );
  Timer.Interval := DispTime * 1000;
  Timer.Enabled := True;
end;

//-------------------- Button 類 -------------------------
procedure TForm1.Button1Click(Sender: TObject);
begin
  PostLabelText(Label1, 'タイマースタート', 3);
  Button1.Enabled := False;
  Button2.Enabled := False;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Close;
end;

end.

download CreateAnonymousThread.zip



      最初に戻る