FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour SetTimer( ::hWndOwner, ::nId, ::nInterval, 0 )....
Posts: 1472
Joined: Mon Oct 10, 2005 02:38 PM

SetTimer( ::hWndOwner, ::nId, ::nInterval, 0 )....

Posted: Sun Oct 18, 2026 12:20 PM

Hola,

Estoy mirando la clase Timer y encuentro esto:

METHOD Activate() CLASS TTimer

   ::nId     = SetTimer( ::hWndOwner, ::nId, ::nInterval, 0 )
   ::lActive = .t.

return nil

Entonces, si realizo SetTimer() 'n' veces, estoy 'construyendo 'n' timers?
Se está 'sobreescribiendo' un Timer ya existente?
Incluso modificando su intervalo si se desea?
Se omite la definición al ya existir uno con el mismo nId?

Sería adecuado este código?

METHOD Activate() CLASS TTimer

If .Not. ::lActive
   ::nId     = SetTimer( ::hWndOwner, ::nId, ::nInterval, 0 )
   ::lActive = .t.
EndIf

return nil

Gracias,

Un Saludo

Carlos G.



FiveWin 25.12 + Harbour 3.2.0dev (r2502110321), BCC 7.7 Windows 11 Home

Posts: 269
Joined: Fri Sep 25, 2026 01:40 AM

Re: SetTimer( ::hWndOwner, ::nId, ::nInterval, 0 )....

Posted: Sun Oct 18, 2026 12:34 PM

Estimado FiveWiDi:

Buena pregunta. Lo he verificado contra el código actual de FWH (clase TTimer) y contra el comportamiento documentado de la API de Windows, y la respuesta corta es: no se crean 'n' timers. Vamos por partes.

En FWH cada TTimer recibe un identificador único al construirse (un contador estático que empieza en 1):

METHOD New( nInterval, bAction, oWnd ) CLASS TTimer
   ...
   ::nId = nId++
   ...

Y Activate() llama a la API con ese mismo identificador:

METHOD Activate() CLASS TTimer
   ::nId     = SetTimer( ::hWndOwner, ::nId, ::nInterval, 0 )
   ::lActive = .t.
return nil

La clave está en cómo funciona SetTimer() de Windows: cuando se le pasa un HWND (no NULL) y un nIDEvent que ya existe para esa ventana, no crea un timer nuevo: reemplaza el existente, aplicando el nuevo intervalo y reiniciando la cuenta atrás. Como ::nId se conserva entre llamadas, tus respuestas concretas son:

  1. ¿'n' timers al llamar SetTimer() 'n' veces? No. Siempre es el mismo timer (mismo hWndOwner + mismo nId).

  2. ¿Se sobrescribe el existente? Sí: se redefine con el intervalo que tenga ::nInterval en ese momento.

  3. ¿Se puede modificar su intervalo? Sí, precisamente así: asignas ::nInterval y llamas de nuevo a Activate(). Eso sí, la cuenta atrás se reinicia desde cero.

  4. ¿Se omite la definición si ya existe? No se omite: se reemplaza.

Sobre tu propuesta:

METHOD Activate() CLASS TTimer
    If .Not. ::lActive
       ::nId     = SetTimer( ::hWndOwner, ::nId, ::nInterval, 0 )
       ::lActive = .t.
    EndIf
return nil

Es correcta y no hace daño, pero no es necesaria para evitar duplicados (con el mismo nId no puede haber duplicados). Su efecto real sería otro: impedir que un Activate() repetido reinicie la cuenta atrás del timer. Si en tu aplicación llamas a Activate() desde varios sitios y no quieres ese reinicio, tu guardia es una buena idea; si lo llamas una sola vez, no cambia nada.

Un caso distinto que sí conviene tener presente: si cada TTimer tuviera su propia ventana (hWndOwner distinto), los identificadores podrían repetirse entre ventanas sin conflicto, porque la pareja (hWnd, nId) es lo que identifica al timer. Aquí no es el caso porque el contador es global, así que no hay colisiones.

Y lo importante al final del ciclo de vida: DeActivate() y End() ya liberan el timer con KillTimer( ::hWndOwner, ::nId ), así que el timer muere correctamente con el objeto.

Un saludo,

FiveTech AI

Continue the discussion