独立线程实现消息循环的Delphi定时器类

独立线程实现消息循环的Delphi定时器类 收藏

Delphi的定时器类TTimer内部是创建不可见的窗口,调用SetTimer这个Win32 API 来实现的。TTimer要求使用它的线程实现了消息循环。所以,除非控制台程序中实现消息循环,否则TTimer在控制台程序中是无效的。不过为了使用方便,可以我们写一个线程类来实现消息循环,并且不必创建隐藏窗口便可以使用定时器。下面面的TSfTimerThread就是这样的类,它可以在不终止线程的情况下改变定时间隔和定时触发的函数。不过目前Enable属性是利用是否进行回调来实现的,也就是Enable设置为False时,定时器依然有效,并且线程会收到WM_TIMER消息,只是收到消息后不进行回调。由于关闭定时测试没有通过,所以暂时这样实现。

{ Timer Utility Library ,Copyright (c) Zhou Zuoji }      

unit SfTimerThread
interface
uses
    Classes
,
    SysUtils
,
    Windows
,
    SfException;
type
    TWin32TimerProc 
= procedure( WndHandle: THandle; uMsg: UINT; idEvent: UINT_PTR; dwTime: DWORD ); stdcall;
    TSfTimerProc 
= procedure(Param:Integer;ATimerID: Cardinal; dwTickCount: Cardinal ) of object;
    TSfTimerThread 
= class( TThread )
    
private
        FTimerID
: Cardinal;
        FTimerProc
: TSfTimerProc;
        FInterval
: Cardinal;
        FTimerProcSyncExec
: Boolean;
        FUpdateRequired
: Boolean;
        FKillRequired
: Boolean;
        FMessage
: TMsg;
        FEnabled
: Boolean;
        FParam
: Integer;
        
function CreateTimer: Boolean;
        procedure DestroyTimer;
        
function AdjustTimerInterval( AInterval: Cardinal ): Cardinal;
    
protected
        procedure SetInterval( 
const Value: Cardinal );
        procedure SetTimerProc( 
const Value: TSfTimerProc );
        procedure SetEnabled( 
const Value: Boolean );
        procedure Timer; dynamic;
        procedure Execute; override;
    
public
        constructor Create( ATimerProc
: TSfTimerProc; AParam: Integer = 0;AInterval: Cardinal = 1000;
            CreateSuspend
: Boolean = False );
        destructor Destroy; override;
        property Interval
: Cardinal read FInterval write SetInterval;
        property TimerID
: Cardinal read FTimerID;
        property TimerProc
: TSfTimerProc read FTimerProc write SetTimerProc;
        property TimerProcSyncExec
: Boolean read FTimerProcSyncExec write FTimerProcSyncExec;
        property Enabled
: Boolean read FEnabled write SetEnabled;
    
end;
implementation
{ TSfTimerThread }
procedure DefaultTimerProc( WndHandle
: THandle; uMsg: UINT; idEvent: UINT_PTR; dwTime: DWORD ); stdcall;
begin
end;
function TSfTimerThread.AdjustTimerInterval( AInterval: Cardinal ): Cardinal;
begin
    
if AInterval = 0 then
        Result 
:= 1000
    
else Result := AInterval;
end;
constructor TSfTimerThread
.Create( ATimerProc: TSfTimerProc;AParam: Integer ;AInterval: Cardinal; CreateSuspend: Boolean );
begin
    inherited Create( CreateSuspend );
    FInterval 
:= AdjustTimerInterval( AInterval );
    @FTimerProc 
:= @ATimerProc;
    FTimerID 
:= 0;
    FTimerProcSyncExec 
:= False;
    FUpdateRequired 
:= False;
    FKillRequired 
:= False;
    FEnabled
:=True;
    FParam
:=AParam;
end;
function TSfTimerThread.CreateTimer: Boolean;
begin
    DestroyTimer;
    FTimerID 
:= Windows.SetTimer( 0, 0, FInterval, @DefaultTimerProc );
    Result 
:= FTimerID > 0;
    
//FEnabled := Result;
    if not Result then
        SfRaiseException(nil
,'create timer failed');
end;
destructor TSfTimerThread
.Destroy;
begin
    DestroyTimer;
    inherited;
end;
procedure TSfTimerThread
.DestroyTimer;
begin
    
if FTimerID > 0 then
    begin
        Windows
.KillTimer( 0, FTimerID );
        FTimerID 
:= 0;
        
//FEnabled := False;
    end;
end;
procedure TSfTimerThread
.Execute;
const
    WM_TIMER 
= $0113;
begin
    inherited;
    CreateTimer;
        
while not Terminated and GetMessage( FMessage, 0, 0, 0 ) do
        begin
            TranslateMessage( FMessage );
            
if ( FMessage.message = WM_TIMER ) and ( Cardinal(FMessage.wParam) = FTimerID )
              and FEnabled then
                
if FTimerProcSyncExec then
                    Synchronize( Timer )
                
else
                    Timer;
            
if FUpdateRequired then
            begin
                CreateTimer;
                FUpdateRequired 
:= False;
            
end;
            {
if FKillRequired then
            begin
                DestroyTimer;
                FKillRequired
:=False;
            
end;}
        
end;
    DestroyTimer;
end;
procedure TSfTimerThread
.SetEnabled( const Value: Boolean );
begin
    
if FEnabled <> Value then
    begin
        {
if Value then
            FUpdateRequired 
:= True
        
else
            FKillRequired 
:= True;}
        FEnabled
:=Value;
    
end;
end;
procedure TSfTimerThread
.SetInterval( const Value: Cardinal );
begin
    
if ( FInterval <> AdjustTimerInterval( Value ) ) then
    begin
        FInterval 
:= AdjustTimerInterval( Value );
        FUpdateRequired 
:= True;
    
end;
end;
procedure TSfTimerThread
.SetTimerProc( const Value: TSfTimerProc );
begin
    
if not Terminated and ( @FTimerProc <> nil ) then
        FTimerProc 
:= Value;
end;
procedure TSfTimerThread
.Timer;
begin
    
try
        
if @FTimerProc <> nil then
            FTimerProc(FParam 
,FMessage.wParam, FMessage.time );
    except
    
end;
end;
end.

posted @ 2011-10-06 23:20  懒猫的博客  阅读(887)  评论(0)    收藏  举报