Myślę, że możesz opuścić numer TTimer
, tak jak jest, i spróbować użyć funkcji SetTimer
i skorzystać z funkcji zwrotnej. Musisz przechowywać identyfikatory timerów i ich (anonimowe) metody w niektórych kolekcjach. Ponieważ nie wspomniałeś o swojej wersji Delphi, użyłem prostych klas i TObjectList
jako kolekcji.
Zasada jest prosta, wystarczy wywołać funkcję SetTimer
z określoną funkcją wywołania zwrotnego i zapisać nowy instancjonowany identyfikator zegara systemowego z anonimową metodą do kolekcji. Gdy wykonywana jest ta funkcja oddzwaniania, znajdź licznik czasu, który spowodował wywołanie zwrotne w kolekcji według jego identyfikatora, zabij go, wykonaj anonimową metodę i usuń go z kolekcji. Oto przykładowy kod:
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.
wersja uproszczona (Delphi 2009 w górę):
jak sugeruje @ komentarz Dawida, tutaj jest ten sam kod jak wyżej, tylko w oddzielnym jednostka za pomocą słownika generycznego. Korzystanie z SetTimeout
z tego urządzenia jest taka sama jak w powyższym kodzie:
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.
Nie mogę zrozumieć tego. Czy mógłbyś spróbować opracować proszę. –
Chcesz szybki i brudny jednorazowy timer.A następnie można go zawinąć w funkcję setTimeout dla wygody. –