这setTimeout
对 JavaScript 语言很有帮助。你将如何在 delphi 中创建这个函数?
SetTimeOut(procedure (Sender: TObject);
begin
Self.Counter := Self.Counter + 1;
end, 200);
这setTimeout
对 JavaScript 语言很有帮助。你将如何在 delphi 中创建这个函数?
SetTimeOut(procedure (Sender: TObject);
begin
Self.Counter := Self.Counter + 1;
end, 200);
我认为您可以保持TTimer
原样并尝试使用该SetTimer
函数并使用它的回调函数。您需要将计时器 ID 及其(匿名)方法存储在某个集合中。因为你没有提到你的 Delphi 版本,所以我使用了一个简单的类和TObjectList
一个集合。
原理很简单,只要调用SetTimer
指定回调函数的函数,用匿名方法将新实例化的系统定时器ID存入集合即可。当执行该回调函数时,通过其 ID 在集合中找到导致该回调的计时器,将其杀死,执行匿名方法并将其从集合中删除。这是示例代码:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, Contnrs;
type
TOnTimerProc = reference to procedure;
TOneShotTimer = class
ID: UINT_PTR;
Proc: TOnTimerProc;
end;
procedure SetTimeout(AProc: TOnTimerProc; ATimeout: Cardinal);
type
TForm1 = class(TForm)
Timer1: TTimer;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
TimerList: TObjectList;
implementation
{$R *.dfm}
procedure TimerProc(hwnd: HWND; uMsg: UINT; idEvent: UINT_PTR;
dwTime: DWORD); stdcall;
var
I: Integer;
Timer: TOneShotTimer;
begin
for I := 0 to TimerList.Count - 1 do
begin
Timer := TOneShotTimer(TimerList[I]);
if Timer.ID = idEvent then
begin
KillTimer(0, idEvent);
Timer.Proc();
TimerList.Delete(I);
Break;
end;
end;
end;
procedure SetTimeout(AProc: TOnTimerProc; ATimeout: Cardinal);
var
Timer: TOneShotTimer;
begin
Timer := TOneShotTimer.Create;
Timer.ID := SetTimer(0, 0, ATimeout, @TimerProc);
Timer.Proc := AProc;
TimerList.Add(Timer);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SetTimeout(procedure
begin
ShowMessage('OnTimer');
end,
1000
);
end;
initialization
TimerList := TObjectList.Create;
TimerList.OwnsObjects := True;
finalization
TimerList.Free;
end.
简化版(Delphi 2009 以上):
就像@David 的评论所建议的那样,这里是与上面相同的代码,只是在一个单独的单元中使用泛型字典。本单元中的用法SetTimeout
与上面的代码相同:
unit OneShotTimer;
interface
uses
Windows, Generics.Collections;
type
TOnTimerProc = reference to procedure;
procedure SetTimeout(AProc: TOnTimerProc; ATimeout: Cardinal);
var
TimerList: TDictionary<UINT_PTR, TOnTimerProc>;
implementation
procedure TimerProc(hwnd: HWND; uMsg: UINT; idEvent: UINT_PTR;
dwTime: DWORD); stdcall;
var
Proc: TOnTimerProc;
begin
if TimerList.TryGetValue(idEvent, Proc) then
try
KillTimer(0, idEvent);
Proc();
finally
TimerList.Remove(idEvent);
end;
end;
procedure SetTimeout(AProc: TOnTimerProc; ATimeout: Cardinal);
begin
TimerList.Add(SetTimer(0, 0, ATimeout, @TimerProc), AProc);
end;
initialization
TimerList := TDictionary<UINT_PTR, TOnTimerProc>.Create;
finalization
TimerList.Free;
end.
就像是
type
TMyProc = Procedure of Object(Sender: TObject);
TMyClass = Object
HandlerList = TStringList;
TimerList = TStringlist;
Procedure CallThisFunction(Sender :TObject);
function setTimeout(Timeout: Integer; ProcToCall : TMyProc)
end;
function setTimeout(Timeout: Integer; ProcToCall : TMyProc)
var
Timer : TTimer;
begin
Timer := TTimer.Create(nil);
Timer.OnTimer := CallOnTimer;
Timer.Interval := Timeout;
Timer.Enabled := true;
HandlerList.AddObject(ProcToCall);
TimerList.AddObject(ProcToCall);
end;
function CallOnTimer(Sender : TObject)
var TimerIndex : Integer;
HandlerToCall : TMyProc;
Timer : TTimer;
begin
TimerIndex := TimerList.IndexOfObject(Sender);
HandlerToCall := (HandlerList.Objects[TimerIndex] as TMyProc) ;
HandlerToCall(Self);
HandlerList.Delete(TimerIndex);
Timer := (TimerList.Objects(TimerIndex) as TTimer);
Timer.Free;
TimerList.Delete(TimerIndex);
end;
这刚刚被破解在一起,没有以任何方式进行测试,但显示了这个概念。基本上建立一个你想要调用的计时器和程序的列表。因为它是 self 对象在调用时传递给过程,但您可以构建第三个列表,其中包含要用作 setTimeout 调用中的参数的对象。
然后在调用方法后通过释放来清理对象。
与 javascripts setTimeout 不完全相同,而是一个 delphi 近似值。
附言。我还没有真正从 Delphi7 继续前进,所以如果在 Delphi XE 中有一种新的方法可以做到这一点,我不知道。
假设该函数每秒被调用一次而不是 5 次,可能是这样的:
Parallel.Async(
procedure; begin
Sleep(200);
Self.Counter:=Self.Counter+1; end; );
还有更复杂的解决方案,例如您接受的解决方案,将命名对象用于计时器操作并使用 SetTimer 方法。像http://code.google.com/p/omnithreadlibrary/source/browse/trunk/tests/17_MsgWait/test_17_MsgWait.pas 以前的版本有带有匿名功能的 SetTimer,但现在已经不存在了。
但是,对于您要求的简单匿名关闭方法,也许 Wait(xxxX) 适合。
我通常这样做
TThread.CreateAnonymousThread(procedure begin
Sleep(1000); // timeout
// put here what you want to do
end).Start;