亲爱的Delphi程序员,
我正在寻求帮助如何编写一个一次性计时器(没有GUI,所以VCL计时器是不可能的).
让我再解释一下。
在我的代码中(用VCL计时器解释,但在这个特定的项目中,我没有表单):
procedureInterval的计时器在OnTimer事件中:
我有一个代码,它发送一个字符,然后禁用定时器本身,使其不再被执行。
问题是,我需要使这些定时器的创建动态。我想到了函数SetTimer(),然后KillTimer()在"OnTimer事件“中禁用它(释放它)。
这是一种好的(安全的)方法吗?
谢谢!
发布于 2012-12-19 01:57:03
从计时器事件内部杀死计时器安全吗?
是的,那很安全。
如何实现最简单的一次定时器?
一个1秒一秒计时器最简单的实现是这样的,但是请注意,如果启动更多这样的定时器,您将无法区分其中哪一个过了它的间隔:
procedure TimerProc(hwnd: HWND; uMsg: UINT; idEvent: UINT_PTR;
dwTime: DWORD); stdcall;
begin
KillTimer(0, idEvent);
ShowMessage('I''m done!');
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SetTimer(0, 0, 1000, @TimerProc);
end;发布于 2012-12-19 06:39:28
多媒体计时器API提供对一次性计时器的支持。好处是,时间比SetTimer/KillTimer解决方案精确得多,您可以在间隔小于50 ms的情况下使用它。这是有代价的,因为回调不会在主线程的上下文中返回。下面是我使用多媒体计时器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.发布于 2013-06-03 14:08:52
您是否意识到,只要您有窗口句柄,就不需要有GUI,就可以使用VCL计时器吗?您可以简单地通过以下方法从代码中实例化一个
fTimer := TTimer.Create(hWindowHandle);即使您没有窗口句柄,也可以通过调用
fVirtualWindowHWND := AllocateHWnd(WndMethod);但在这种情况下,您还必须编写自己的消息循环。我知道调用Windows似乎是一个更容易的解决方案,但它也有自己的caveeats (就像您不能将类方法传递给它.),我想,您可能想知道这个方法。
https://stackoverflow.com/questions/13944301
复制相似问题