Newsgroup: it.comp.lang.delphi
Titolo: Correttezza del componente Timer

Salve a tutti,
dovrei creare una specie di cronometro: ho usato tre campi memo in cui
vengono visualizzati ore, minuti e secondi; quando viene premuto il
pulsante di avvio viene abilitato un componente Timer che, ogni
secondo (Interval è infatti settato a 1000) richiama una procedura che
incrementa la variabile secondi di uno e visualizza nel campo memo il
nuovo valore dei secondi.
Il problema è che i conteggi del componente timer non sembrano
affidabili: il cronometro dopo un minuto di tempo ha già uno scarto
(in difetto) di qualche secondo, come mai?
E' possibile che la velocità del cronometro sia in qualche modo
influenzata da altri fattori (velocità del processore, complessità
della procedura che deve eseguire, etc...)
Uso Delphi 4 standard.
Grazie.
Lupin 
hpage: 
http://i.am/eugenio
 ---> 
www.agonet.it/~eugenio.t/
Co-Webmaster di HTMLBox 
www.htmlbox.cjb.net

della procedura che deve eseguire, etc...)
il problema del timer è una questione che riguarda i messaggi che lui invia
alla coda dell' applicazione, ma questi potrebbero essere annullati o
valutati con qualche istante di ritardo che in un minuto ti riporta lo
scarto di pochi secondi. Anche se ti impegni ottimizzando un po' tutte le
routine della tua applicazione, un po' di errore c' è sempre.
Al limite potresti fare un thread dedicato proprio al Timer, oppure
utilizzare l' API GetTickCount che ti ritorna il tempo in millisecondi da
quando è stato avviato Windows.
In alternativa ci sono i Timer Multimediali che dovrebbero essere più
precisi.
Sul repository di MrCoke nei newsgroup di Marco Cantù "
news.marcocantu.it
"
ci dovrebbe essere un esempio (con tanto di codice completo ovviamente) di
questo benedetto Timer Multimediale.
Se non lo trovi ricordo che stava nel vecchio repository di Mr Coke ma poi
quel news è stato chiuso e non so se ancora sia possibile scaricare i
messaggi. L' indirizzo era: 
news.dms.it
Se proprio non riesci a trovarlo, scrivimi in privato, ma non ti assicuro
nulla perchè devo prima controllare di averlo io nei messaggi del
repository.
Ti saluto.....ciaooooo !!!
Antonio Tarolla
BSSoftware Tips Mailing - List Support

 (in difetto) di qualche secondo, come mai?
Ciao,
        il componente Timer (che si basa sull'API SetTimer) è
sostanzialmente un gestore di evento: tramite una chiamata alla suddetta
funzione SetTimer egli "registra" al sistema la necessità di ricevere un
messaggio WM_TIMER ogni x millisecondi...
Il problema di questo sistema è che il WM_TIMER è un messaggio e,come tutti
gli altri, viene inviato alla coda dei msg di un'applicazione (in sostanza
passa nella WndProc) e questo significa dimenticarsi di avere una precisione
decente.
Per avere temporizzazioni un po' + precise ti conviene di + usare un thread
e utilizzare la funzione sleep() ma anche qui non otterrai risultati + di
tanto apprezzabili.
Per quello che devi fare io farei ciclo (non continuo, mi raccomando)
controllando la differenza di tempo su due variabili TDateTime o, se
preferisci, sul valore Longint che ti ritorna la GetTickCount [il tempo,in
millisecondi, da quando è stato caricato il Kernel di Win32].
Ciao :-)
--
(¯`·.¸¸.·´¯`·.¸¸.-> Andrea <-.¸¸.·´¯`·.¸¸.·´¯)
AntiSpam: rimuovere il trattino basso dall'indirizzo per rispondere
AntiSpam: remove the underscore from the e-mail address to reply

precisi.
[....]
Ringrazio te e Andrea per le risposte, penso di aver risolto in questo
modo: ho impostato il timer a un intervallo di un millisecondo, ogni
millisecondo una procedura controlla che non sia cambiato l'orologio
di Win, se è cambiato aggiunge un secondo al tempo. Certo non è il
massimo dell'efficienza però sembra funzionare (dopo una decina di
minuti non ho notato sfasamenti), magari provo ad aumentare
l'intervallo per vedere se comunque resta affidabile.
Se non funziona bene mi sa che ti dovrò disturbare per il Timer
Multimediale ;) a proposito, cosa sarebbe di preciso, perchè
"multimediale"?



Multimediale perche' la sua implementazione da parte dei programmatori
Microsoft e' andato a finire in mezzo alle funzioni multimediali, per le
quali e' indispensabile.
Ciao,
Stefano

    Intervallo := GetTickCount - ValoreZero;
[....]
Grazie per l'ulteriore soluzione ;)
Perchè secondo te è più conveniente usare GetTickCount? A parità di
intervallo utilizzato le due soluzioni dovrebbero consumare più o meno
le stesse risorse, mi sbaglio?



55ms per la precisione (su win95/98, mentre su WinNT la precisione mi pare
sia settabile).
Roal Zanazzi

 wrote in message
news:85kc4h$bls$1...@pegasus.tiscalinet.it...

Acc... mi ricordavo pure male. Pero' ripensandoci mi sembrava troppo poco
5ms
Ciao,
Stefano


Vero, ma mentre il GetTickCount e' una funzione molto veloce, la funzione di
richiesta dell'ora di sistema credo sia un pochino + lenta ed e' comunque
inutile visto che a te serve un tempo relativo.
Cmq se ti garba di + puoi usarla ugualmente ;-)
Ciao,
Stefano



Ho fatto un paio di test (utilizzando il meccanismo di richiesta
dell'ora al sistema); la cosa incredibile è che:
sul mio k6-200 + win95 il conteggio dei secondi è piuttosto preciso
(dopo un'ora e mezza era ancora OK)
su un PIII 450 + win98 il cronometro "perde" 5 secondi ogni ora! Com'è
possibile? La cosa è da imputare al processore o a win98?
Preciso che al posto del componente TIMER di Delphi ho utilizzato un
componente free dal nome ThreadedTimer (v1.2), che dovrebbe
incrementare l'affidabilità del timer.



Dipende da come hai operato. Mi e' difficile fare delle ipotesi.
Prova a postare la parte di codice che hai messo nell'evento OnTimer
Ciao,
Stefano



Ho riprovato sullo stesso computer (il PIII) e non si è più verificato
il problema...il cronometro funzionava...comunque il codice è molto
semplice, ogni millisecondo viene eseguito un confronto
if OraCorrente <> TimeToStr(Time) then
begin
Secondi := Secondi + 1;
OraCorrente := TimeToStr(Time);
.....
Poi c'è una serie di if...then annidati che eseguono altri confronti.


 wrote in message
news:38877438...@news.agonet.it...

Immaginavo fosse qualcosa del genere. Questo e' un modo scorretto di
operare.
Infatti, supponendo che il timer esegua veramente quella parte di codice
ogni millisecondo, devi tener conto del fatto che le istruzioni che tu
esegui occupano del tempo e che, tra l'altro, tu confronti e assegni 2
valori diversi di Time.
Un modo un pochino + corretto sarebbe questo:
OraAttuale := TimeToStr(Time);
if OraCorrente <> OraAttuale then
begin
  Secondi := Secondi + 1;
  OraCorrente := OraAttuale;
Ma un modo ancora migliore sarebbe quello di impostare una variabile globale
(o di classe) che mantenga l'ora iniziale (o meglio i Tick, che sono in
millisecondi) e fare una routine del genere, supponendo che quando lanci il
tuo cronometro tu esegua:
TickIniziale := GetTick;
ad ogni esecuzione del Timer (che puo' essere superiore ad un millisecondo,
magari un 10 ms va benissimo) fai:
Secondi := (GetTick - TickIniziale) div 1000;
Mi sembra + veloce e + sicuro, visto che e' un valore assoluto e non dipende
dalla correttezza del timer
Ciao,
Stefano

Un modo un pochino + corretto sarebbe questo:
[....]
Grazie 1000 per i consigli.
