That means you are creating the TTimer in the main thread to begin with, not in the background thread.
That's exactly how TTimer already works. Its constructor creates a hidden window in the calling thread, which when activated will then receive timer messages from that same thread. So the thread that creates the TTimer must have a message loop to receive and dispatch those timer messages. So, you might think about moving the creation of the TTimer into the background thread's Execute() method, and that may work 99% of the time, but know that the creation of that hidden window is not done in a thread-safe manner, so you really should not be using TTimer in a background thread at all.
If you really need a thread-based timer, you could just use the Win32 timeSetEvent() function, which is a multimedia timer that runs its callback in a background thread that the OS manages,
If you really want to use a custom TThread class, then using TEvent is the simplest option that allows you to terminate the thread on demand, eg:
uses
..., Classes, SyncObjs;
type
TTimerThread = class (TThread)
private
fEvent: TEvent;
fInterval: LongWord;
fOnElapsed: TNotifyEvent;
protected
procedure Execute; override;
procedure TerminatedSet; override;
public
constructor Create(AInterval: LongWord; AOnElapsed: TNotifyEvent); reintroduce;
destructor Destroy;
end;
constructor TTimerThread.Create(AInterval: LongWord; AOnTimer: TNotifyEvent);
begin
inherited Create(False);
fInterval := AInterval;
fOnElapsed := AOnElapsed;
fEvent := TEvent.Create;
end;
destructor TTimerThread.Destroy;
begin
fEvent.Free;
inherited Destroy;
end;
procedure TTimerThread.TerminatedSet;
begin
fEvent.SetEvent;
end;
procedure TTimerThread.Execute;
begin
while fEvent.WaitFor(fInterval) = wrTimeout do
fOnElapsed(Self);
end;