2012-05-06 27 views
17

El setTimeout es útil en JavaScript. ¿Cómo crearías esta función en Delphi?¿Cómo hacer una función de temporizador de disparo en Delphi (como setTimeout en JavaScript)?

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

no puedo dar sentido a esto. ¿Podrías tratar de elaborar por favor? –

+0

Quieres un temporizador rápido y sucio de una sola vez.Y luego puede envolverlo en una función setTimeout para su comodidad. –

Respuesta

24

Creo que puede dejar el TTimer tal como está y tratar de usar la función SetTimer y usar su función de devolución de llamada. Necesita almacenar las ID del temporizador y sus métodos (anónimos) en alguna colección. Como no mencionó su versión de Delphi, he usado una clase simple y TObjectList como una colección.

El principio es fácil, solo llame a la función SetTimer con la función de devolución de llamada especificada y almacene en la colección la nueva identificación del temporizador del sistema instanciado con el método anónimo. Cuando se realiza esa función de devolución de llamada, busque el temporizador que causó esa devolución de llamada en la colección por su ID, elimínelo, ejecute el método anónimo y elimínelo de la colección. Aquí está el código de ejemplo:

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. 


versión simplificada (Delphi 2009 hasta):

Como sugerido por @ el comentario de David, aquí es el mismo código que anteriormente, justo a una por separado unidad con el uso de diccionario de genéricos. Uso de la SetTimeout de esta unidad es la misma que en el código anterior:

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

¡Es una pieza de código realmente interesante, muy bien hecha! – Pateman

+0

Debe ejecutar ese ciclo hacia atrás porque lo elimina de la lista que itera sobre –

+0

@David, no es necesario aquí. Estoy eliminando solo un elemento y rompiendo el ciclo. – TLama

1

Algo así como

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; 

Esto sólo ha sido hackeado juntos y no probado en modo alguno sino que muestra el concepto. Básicamente construya una lista de los temporizadores y procedimientos a los que desea llamar. Como es el autoobjeto, se pasa al procedimiento cuando se lo llama, pero se puede construir una tercera lista que contenga el objeto que se utilizará como parámetro en la llamada a setTimeout.

Los Objetos se limpian luego de liberar el método.

No es exactamente lo mismo que javascripts setTimeout pero una aproximación delphi.

ps. Realmente no me he movido de Delphi7, así que si hay una nueva forma de hacer esto en Delphi XE, no lo sé.

+0

no, quiero usar [función anónima] (http://delphi.about.com/od/objectpascalide/a/understanding-anonymous-methods-in-delphi.htm). su puntero de método de uso de código. – MajidTaheri

0

Suponiendo, la función debe ser llamada una vez y no 5 veces cada segundo, tal vez así:

Parallel.Async( 
     procedure; begin 
      Sleep(200); 
      Self.Counter:=Self.Counter+1; end;); 

Hay son soluciones más complejas como la que usted aceptó, tomando objetos nombrados para acciones de temporizador y usando el método SetTimer. Como http://code.google.com/p/omnithreadlibrary/source/browse/trunk/tests/17_MsgWait/test_17_MsgWait.pas Las versiones anteriores tenían SetTimer con función anónima, pero ya no están.

Sin embargo, para el enfoque de cierre anónimo simplificado que solicitó, tal vez Esperar (xxX) cabría.

0

por lo general lo hago de esta manera

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

    // put here what you want to do 

end).Start; 
Cuestiones relacionadas