2012-05-06 65 views
17

setTimeout對JavaScript語言很有幫助。你將如何在delphi中創建這個功能?如何在Delphi中創建一個定時器函數(如JavaScript中的setTimeout)?

SetTimeOut(procedure (Sender: TObject); 
begin 
    Self.Counter := Self.Counter + 1; 
end, 200); 
+2

我無法理解這一點。你能否試着詳細說明一下。 –

+0

你想要一個快速和骯髒的一次性定時器。然後,您可以將其封裝在setTimeout函數中以方便使用。 –

回答

24

我想你可能會離開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. 


簡體版(德爾福2009年增長):

像通過@大衛的評論,下面是相同的代碼上面,只是在一個單獨的建議單位與使用泛型字典。從本機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. 
+4

這是一段非常有趣的代碼,很好地完成了! – Pateman

+0

您需要向後運行該循環,因爲您從列表中刪除了迭代 –

+0

@David,這裏不需要。我只刪除了一個項目並打破了循環。 – TLama

1

喜歡的東西

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; 

這剛剛被黑客攻擊在一起,而不是測試以任何方式,表示的是概念。基本上建立你想要調用的定時器和過程的列表。由於自身對象在被調用時被傳遞給過程,但是您可以構建第三個包含要在setTimeout調用中用作參數的對象的列表。

然後在調用該方法後釋放對象。

與javascripts setTimeout不同,但是與delphi近似。

ps。我還沒有真正從Delphi7上移開,所以如果在Delphi XE中有這樣一個新的混亂的方式,我不知道它。

+0

不,我想用[匿名函數](http://delphi.about.com/od/objectpascalide/a/understanding-anonymous-methods-in-delphi.htm)。你的代碼使用方法指針。 – MajidTaheri

0

假設,該功能將被調用一次,而不是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(xxX)會適合。

0

我平時做這樣

TThread.CreateAnonymousThread(procedure begin 
    Sleep(1000); // timeout 

    // put here what you want to do 

end).Start; 
相關問題