Delphi: OnTimer event of my own Timer never happens
Asked Answered
H

3

7

I need a Timer in a 'no form' Delphi unit (there's still a main unit with a form), so I do this:

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);

The problem is that the OnMyTimer procedure is never run. I'll truly appreciate any ideas as to why :-)

Highgrade answered 14/4, 2010 at 6:9 Comment(0)
R
6

Apart from the fact you created a MyTimer and freed a MouseTimer, I don't see anything wrong with your code (I do assume you use your code in a GUI application or at least are having a message loop)

This code sample works with Delphi 5. The Hello Worldget's written to the eventlog every second.

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.
Ringnecked answered 14/4, 2010 at 6:30 Comment(2)
I don't know why, but I made it work by rearranging units in the uses sections (ExtCtrls in interface, SysUtils and Windows in implementation). Go figure :-)Highgrade
Mikhail, I assure you the units' usage order had no effect on your program's success. The problem was elsewhere.Bilabial
B
10

In order for a timer to work, your program must process messages. In a GUI program, that part is automatic; the TApplication class provides that for you. But you say you have a "no form" program, so I suppose you're probably not calling Application.Run in your DPR file.

To use a timer, you need to process messages. The typical starting point for a message pump is code like this:

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

When a timer's period has elapsed, the OS effectively places a wm_Timer message in your program's message queue. The GetMessage call fetches messages from the queue, and DispatchMessage calls the destination window's window procedure. TTimer creates a hidden window for itself to serve as the target for those messages, and DispatchMessage makes sure they get there.

Bilabial answered 14/4, 2010 at 8:31 Comment(3)
Often creating a message loop just to use a timer seems overkill to me. You can use other mechanism tha work better in threads and similar objects. WaitForSingle object for instance etc...Thrall
Absolutely. I could have gone on at length about alternatives to TTimer, but I decided to limit my answer to the question at hand.Bilabial
I meant no disrespect. I just wanted, if somebody reads it, that they are aware of this.Thrall
R
6

Apart from the fact you created a MyTimer and freed a MouseTimer, I don't see anything wrong with your code (I do assume you use your code in a GUI application or at least are having a message loop)

This code sample works with Delphi 5. The Hello Worldget's written to the eventlog every second.

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.
Ringnecked answered 14/4, 2010 at 6:30 Comment(2)
I don't know why, but I made it work by rearranging units in the uses sections (ExtCtrls in interface, SysUtils and Windows in implementation). Go figure :-)Highgrade
Mikhail, I assure you the units' usage order had no effect on your program's success. The problem was elsewhere.Bilabial
G
1

Is your unit used by other units or not? If this unit isn't used by others it won't even get in the initialization section. Or maybe the unit is finalized sooner then you think.

Put a breakpoint at the MyTimer := TMyTimer.Create(nil); line and at the FreeAndNil(MyTimer) line and run your application. Make sure that the timer is created when you want it to and not destroyed too early.

Gaikwar answered 14/4, 2010 at 9:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.