多媒體計時器API提供對單次計時器的支持。好處是,時序比SetTimer/KillTimer解決方案精確得多,您可以在間隔012毫秒的時間內使用它。這是有代價的,因爲回調不會在主線程的上下文中返回。 下面是使用多媒體計時器API我實現一次性的計時器:
unit MMTimer;
interface
uses windows, Classes, mmsystem, SysUtils;
TOneShotCallbackEvent = procedure (const UserData: Pointer) of object;
(*
The MMOneShotCallback function calls the Callback after the Interval passed.
** Attention: **
The Callback is not called within the context of the main thread.
*)
type TMMOneShotTimer = class(TObject)
private
FTimeCaps: TTimeCaps;
FResult: Integer;
FResolution: Cardinal;
public
constructor Create;
function MMOneShotCallback(const Interval: Cardinal; UserData: Pointer; Callback: TOneShotCallbackEvent): Boolean;
property Result: Integer read FResult;
property Resolution: Cardinal read FResolution;
end;
implementation
type
TOneShotCallbackData = record
Callback: TOneShotCallbackEvent;
UserData: Pointer;
end;
POneShotCallbackData = ^TOneShotCallbackData;
procedure OneShotCallback(TimerID, Msg: UINT;
dwUser, dw1, dw2: DWord); pascal;
var pdata: POneShotCallbackData;
begin
pdata := Pointer(dwUser);
pdata.Callback(pdata.UserData);
FreeMemory(pdata);
end;
constructor TMMOneShotTimer.Create;
begin
FResult := timeGetDevCaps(@FTimeCaps, SizeOF(FTimeCaps));
Assert(FResult=TIMERR_NOERROR, 'Call to timeGetDevCaps failed');
FResolution := FTimeCaps.wPeriodMin;
FResult := timeBeginPeriod(FResolution);
Assert(FResult=TIMERR_NOERROR, 'Call to timeBeginPeriod failed');
end;
function TMMOneShotTimer.MMOneShotCallback(const Interval: Cardinal; UserData: Pointer; Callback: TOneShotCallbackEvent): Boolean;
var pdata: POneShotCallbackData;
begin
GetMem(pdata, SizeOf(TOneShotCallbackData));
pdata.Callback := Callback;
pdata.UserData := UserData;
result := (0 <> timeSetEvent(Interval, FResolution, @OneShotCallback, DWord(pdata), TIME_ONESHOT));
if not result then
FreeMemory(pdata);
end;
end.
我前段時間做過['類似的東西](http://stackoverflow.com/q/10468787/960757)。你的方法聽起來不錯,但請注意,如果你一次啓動多個計時器,你需要區分,如果你爲所有計時器使用了一個普通的回調函數,哪一個會觸發該超時。 – TLama
我讀過'SetTimer()'函數,你可以把一個「唯一的ID」給定時器,並通過它們的ID來消滅 – ELCouz
是的,這就是我在代碼中所做的。我正在存儲定時器ID和過程的集合,這些定時器ID和過程應該在定時器間隔過去時執行。發生這種情況時,我在該集合中搜索一個按計時器ID標識的項目,如果發現該項目,我殺死計時器,執行該過程並從集合中刪除找到的項目。 – TLama