2010-04-14 12 views
7

Ho bisogno di un Timer in un 'nessuna forma' unità di Delphi (c'è ancora un'unità principale con un modulo), in modo da fare questo:Delphi: timer evento della mia Timer non accade mai

unit ... 

interface 

type 
    TMyTimer = Class(TTimer) 
    public 
    procedure OnMyTimer(Sender: TObject); 
    end; 

var 
    MyTimer: TMyTimer; 

implementation 

procedure TMyTimer.OnMyTimer(Sender: TObject); 
begin 
    ... 
end; 

initialization 

MyTimer := TMyTimer.Create(nil); 
with MyTimer do 
begin 
    Interval := 1000; 
    Enabled := True; 
    OnTimer := OnMyTimer; 
end; 

finalization 

FreeAndNil(MyTimer); 

Il problema è che la procedura OnMyTimer non viene mai eseguita. Io veramente apprezzato tutte le idee sul perché :-)

risposta

6

A parte il fatto è stato creato un MyTimer e liberato un MouseTimer, non vedo nulla di sbagliato con il codice (io presumo si utilizza il codice in un'applicazione GUI o almeno stanno avendo un ciclo di messaggi)

questo esempio di codice funziona con Delphi 5. il Hello World s get scritto al eventlog ogni secondo.

unit Unit2; 

interface 

uses 
    extctrls; 

type 
    TMyTimer = Class(TTimer) 
    public 
    procedure OnMyTimer(Sender: TObject); 
    end; 

var 
    MyTimer: TMyTimer; 

implementation 

uses 
    windows, sysutils, classes; 

procedure TMyTimer.OnMyTimer(Sender: TObject); 
begin 
    OutputDebugString(PChar('Hello World')); 
end; 

initialization 

MyTimer := TMyTimer.Create(nil); 
with MyTimer do 
begin 
    Interval := 1000; 
    Enabled := True; 
    OnTimer := OnMyTimer; 
end; 

finalization 
    FreeAndNil(MyTimer); 

end. 
+0

Non so perché, ma l'ho fatto riorganizzando le unità nelle sezioni * uses * (ExtCtrls nell'interfaccia, SysUtils e Windows in fase di implementazione). Vai alla figura :-) – Mikhail

+4

Mikhail, ti assicuro che l'ordine di utilizzo delle unità non ha avuto alcun effetto sul successo del tuo programma. Il problema era altrove. –

+0

Devo farlo. –

9

Al fine di un timer per funzionare, il programma deve elaborare i messaggi. In un programma GUI, quella parte è automatica; la classe TApplication lo fornisce per te. Ma tu dici di avere un programma "senza forma", quindi suppongo che probabilmente non stai chiamando Application.Run nel tuo file DPR.

Per utilizzare un timer, è necessario elaborare i messaggi. Il tipico punto di partenza per una pompa messaggio è di codice come questo:

while Integer(GetMessage(Msg, 0, 0, 0)) > 0 do begin 
    TranslateMessage(Msg); 
    DispatchMessage(Msg); 
end; 

Quando periodo di un timer è trascorso, il sistema operativo pone in modo efficace un messaggio wm_Timer nella coda di messaggi del programma. La chiamata GetMessage preleva i messaggi dalla coda e DispatchMessage chiama la procedura della finestra della finestra di destinazione. TTimer crea una finestra nascosta per se stessa per fungere da destinazione per quei messaggi e DispatchMessage si assicura che ottengano lì.

+1

Spesso creare un loop di messaggi solo per usare un timer mi sembra eccessivo. Puoi usare altri meccanismi che funzionano meglio in thread e oggetti simili. Oggetto WaitForSingle per istanza ecc ... – Runner

+0

Assolutamente. Avrei potuto approfondire le alternative a TTimer, ma ho deciso di limitare la mia risposta alla domanda in questione. –

+0

Non volevo mancare di rispetto. Volevo solo, se qualcuno lo leggesse, che ne fossero consapevoli. – Runner

1

L'unità è utilizzata da altre unità o no? Se questa unità non viene utilizzata da altri, non entrerà nemmeno nella sezione di inizializzazione. O forse l'unità è finalizzata prima di quanto pensi.

Inserire un punto di interruzione su MyTimer: = TMyTimer.Create (nil); linea e sulla linea FreeAndNil (MyTimer) ed esegui la tua applicazione. Assicurati che il timer sia creato quando lo vuoi e non distrutto troppo presto.