Penso che si possa lasciare lo TTimer
così com'è e provare a utilizzare la funzione SetTimer
e utilizzare la sua funzione di richiamata. È necessario memorizzare gli ID timer e i loro metodi (anonimi) in alcune raccolte. Dal momento che non hai menzionato la tua versione di Delphi, ho usato una semplice classe e TObjectList
come raccolta.
Il principio è semplice, basta chiamare la funzione SetTimer
con la funzione di callback specificata e archiviare il nuovo ID timer di sistema istanziato con il metodo anonimo nella raccolta. Quando viene eseguita questa funzione di callback, trova il timer che ha causato quella richiamata nella raccolta tramite il suo ID, uccidila, esegui il metodo anonimo ed eliminalo dalla raccolta. Ecco il codice di esempio:
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.
versione semplificata (Delphi 2009 su):
Come suggerito da @ il commento di David, qui è lo stesso codice come sopra, solo in un separato unità con l'uso del dizionario dei generici. Utilizzo della SetTimeout
da questa unità è stesso nel codice sopra:
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.
non riesco a dare un senso a questo. Potresti provare ad elaborare per favore. –
Vuoi un timer one-shot veloce e sporco.E poi puoi avvolgerlo in una funzione setTimeout per comodità. –