单次计时器(One-Shot Timers)

2019-08-04 07:41发布

亲爱的Delphi程序员,

我寻求帮助,如何写单次计时器(没有GUI,因此VCL计时器没问题的)...

让我来解释多一点点。

在我的代码(与VCL计时器解释,但在这个特定的项目我没有形式):

  1. 调用procedure ,其通过串行端口发送一个char
  2. 使得能够与一个X量的计时器Interval

OnTimer事件:

我有送,然后一个char禁用本身永远不会被再次执行计时器代码。

问题是,我需要这些定时器的创作动力。 我认为,功能的SetTimer()然后KillTimer()在“OnTimer事件”来禁用它(释放它)。

它是一个很好的(安全)的方式?

谢谢!

Answer 1:

它是安全的,从一个计时器事件里面杀计时器?

是的,这是完全安全的。

如何实现简单的单次定时器?

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;


Answer 2:

多媒体计时器API提供了一个单次定时器支持。 的好处是,该定时比的SetTimer / KillTimer函数溶液更精确并且可以与间隔<50毫秒使用它。 这是有代价的,因为回调不会在主线程的上下文中返回。 下面是我的实现使用多媒体计时器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.


Answer 3:

你知道,你不必有一个图形用户界面,使用VCL计时器,只要你有一个窗口句柄? 你可以简单地实例化一个从代码通过

fTimer := TTimer.Create(hWindowHandle);

即使你没有一个窗口句柄可以通过调用创建一个

fVirtualWindowHWND := AllocateHWnd(WndMethod);

但在这种情况下,你还可以编写自己的消息循环。 我知道,调用Windows API似乎是一个简单的解决方案,但它也有自己的caveeats(就像你不能传递一个类的方法吧...),我因子评分,你可能想知道这一个。



文章来源: One-Shot Timers