Page 1 sur 1
Timer / Minuterie
Publié : ven. 03/août/2007 18:04
par ThoT
Re bonjour!
J'ai un probleme de comprehension avec les timers.
J'ai trouvé ce code en cherchant sur le forum :
Code : Tout sélectionner
Procedure TimerProc(hwnd.l, uMsg.l, idEvent.l, dwTime.l)
Select uMsg
Case #WM_TIMER
Select idEvent
Case 1
Debug "--------------------1 seconde"
; Ici, le code à executer toutes les secondes
Case 2
Debug "0.2 secondes"
; Ici, le code à executer toutes les 200 millisecondes
Case 3
Debug "-------------------------------------------3 secondes"
; Ici, le code à executer toutes les 3 secondes
EndSelect
EndSelect
EndProcedure
If OpenWindow (0, 100, 100, 100, 100, #PB_Window_SystemMenu , "" )
Handle = WindowID (0)
SetTimer_ (Handle, 1, 1000, @TimerProc()) ; envoie un evenement toutes les 1000 millisecondes
SetTimer_ (Handle, 2, 200, @TimerProc()) ; envoie un evenement toutes les 200 millisecondes
SetTimer_ (Handle, 3, 3000, @TimerProc()) ; envoie un evenement toutes les 3000 millisecondes
Repeat
Until WaitWindowEvent () = #PB_Event_CloseWindow
EndIf
Il fonctionne nickel, mais je souhaiterai des precisions sur son fonctionnement (je n'en trouve pas dans l'aide de PB).
Notament sur les argument de la procedure "TimerProc(hwnd.l, uMsg.l, idEvent.l, dwTime.l)" et sur l'utilité du @ de "SetTimer_ (Handle, 3, 3000, @TimerProc())".
Un grand merci a celui ou celle qui arrivera à m'expliquer tout ca

Publié : ven. 03/août/2007 19:21
par Flype
salut,
c'est normal que tu ne trouves pas de doc dans l'aide purebasic
puisqu'il s'agit de fonctions 'système', provenant directement de l'API Windows (en gros, les dll qui sont dans c:\windows\).
ces fonctions win32 sont différenciées dans pure par un underscore '_' à la fin.
donc la doc pour çà il faut la chercher sur MSDN.
http://msdn2.microsoft.com/en-us/library/ms644906.aspx

Publié : ven. 03/août/2007 19:30
par Flype
et concernant le fonctionnement,
dans cet exemple tu es confronté à 3 choses différentes.
1/ du langage purebasic
2/ une fonction de l'API Win32 (SetTimer)
3/ une fonction 'callback' qui sont si particulières au début.
une fonction callback est une fonction que l'on écrit soi meme (ici TimerProc) mais dont on doit absolument respecter le nombre et le type des arguments (ici hwnd.l, uMsg.l, idEvent.l, dwTime.l) spécifiés par microsoft.
http://msdn2.microsoft.com/en-us/library/ms644907.aspx
une fois écrite, cette fonction pourra être utilisée en la 'passant' à la fonction SetTimer() grace au caractère @ qui indique l'adresse mémoire de la fonction callback (TimerProc).
et donc le but final, est que SetTimer() appelle tout les x temps la fonction callback, indépendamment de ton code principal qui gère le reste de l'application.
en espèrant être assez clair.
Publié : ven. 03/août/2007 20:08
par Droopy
Tu peux facilement générer un timer avec un thread
Code : Tout sélectionner
Procedure Timer()
Repeat
Delay(1000)
beep_(700,100)
ForEver
EndProcedure
CreateThread(@Timer(),0)
Delay(10000)
Publié : ven. 03/août/2007 20:38
par Flype
mais attention, les threads engendrent une programmation plus délicate.
Publié : ven. 03/août/2007 22:36
par ThoT
Ok, comme toujours en programmations plusieurs façons de faire pour un même resultat...
Du coup, j'ai deux interrogations :
1 - Dans le cas present, quels sont les avantages / inconvenients de chacune des solutions (api - thread) ??
2 - Mon abjectif du moment est de réaliser un chronometre.
De ces deux methodes, laquelle serait la plus appropriée?
Publié : ven. 03/août/2007 22:47
par Backup
ThoT a écrit :
2 - Mon abjectif du moment est de réaliser un chronometre.
De ces deux methodes, laquelle serait la plus appropriée?
les timers sont fait pour ça !! plus precis !! indexé sur l'horloge du processeur
alors que les threads ne sont pas aussi precis (temporellement parlant)
a cause des priorités !!..
ils ne sont pas fais pour ça !!
il sont fait pour décharger une partie des calculs pour accelerer un traitement
bref c'est du temps partagé dans un system multitache !!

Publié : ven. 03/août/2007 23:23
par Flype
je dirais que pour un simple chrono de base il n'y a ni besoin de thread, ni de timer. WaitWindowEvent(MilliSecondes) peut suffir dans beaucoup de cas.
Code : Tout sélectionner
Enumeration 0 ; Window Id.
#WindowMain
EndEnumeration
Enumeration 0 ; MenuItem Id.
#MenuItemExit
EndEnumeration
Enumeration 0 ; Gadget Id.
#GadgetStart
#GadgetStop
#GadgetText
#GadgetExit
EndEnumeration
Define timer.l, chrono.l, t.l, s.l, ms.l
LoadFont(0, "Tahoma", 12, #PB_Font_Bold)
If OpenWindow(#WindowMain, 0, 0, 150, 55, "PureChrono", #PB_Window_TitleBar | #PB_Window_ScreenCentered)
SetWindowColor(#WindowMain, RGB(0, 0, 0))
AddKeyboardShortcut(#WindowMain, #PB_Shortcut_Escape, #MenuItemExit)
If CreateGadgetList(WindowID(#WindowMain))
ButtonGadget(#GadgetStart, 5, 5, 50, 20, "Start")
ButtonGadget(#GadgetStop, 60, 5, 50, 20, "Stop")
ButtonGadget(#GadgetExit, 115, 5, 30, 20, "Exit")
TextGadget(#GadgetText, 5, 30, 140, 20, "", #PB_Text_Center)
SetGadgetColor(#GadgetText, #PB_Gadget_FrontColor, RGB(0, 255, 0))
SetGadgetColor(#GadgetText, #PB_Gadget_BackColor, RGB(0, 0, 0))
SetGadgetFont(#GadgetText, FontID(0))
EndIf
Repeat
Select WaitWindowEvent(1) ; <------ attend 1 milliseconde maxi.
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Menu
Select EventMenu()
Case #MenuItemExit
Break
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
Case #GadgetExit
Break
Case #GadgetStart
timer = ElapsedMilliseconds()
chrono = #True
Case #GadgetStop
timer = 0
chrono = #False
EndSelect
Case 0
If chrono
t = ElapsedMilliseconds() - timer
ms = t % 1000
s = t / 1000
SetGadgetText(#GadgetText, RSet(Str(s), 2, "0") + " s " + RSet(Str(ms), 3, "0") + " ms")
EndIf
EndSelect
ForEver
CloseWindow(#WindowMain)
EndIf
End
mais les timers sont bien utiles (et sont fait pour çà aussi).
Publié : sam. 04/août/2007 0:15
par Backup
Flype a écrit : WaitWindowEvent(MilliSecondes) peut suffir dans beaucoup de cas..

j'avais jamais fais gaffe a cette particularité de cette fonction !
ce parametre "MilliSecondes" il n'existe que depuis la V4.10 non ?

Publié : sam. 04/août/2007 0:48
par Flype
depuis la 4.0 mon cher

çà fait un petit moment donc.
Publié : sam. 04/août/2007 9:34
par Droopy
J'avais déjà posté un chrono que je remert ici :
Code : Tout sélectionner
;/ Droopy 05/06/06 / PureBasic 4.0
Global Chrono
Enumeration
#Frame
#Start_Pause
#Reset_Intermediaire
#Chrono
#Status
EndEnumeration
Procedure AffichageChrono()
Repeat
If T<>Chrono ;/ N'affiche le Chrono que si le contenu a changé
ms=(Chrono%1000)/10
Temp.s=Str(ms)
If ms<10
Temp.s="0"+Temp
EndIf
SetGadgetText(#Chrono,FormatDate("%ii:%ss",Chrono/1000)+":"+Temp)
T=Chrono
EndIf
Delay(10)
ForEver
EndProcedure
Procedure Chronometre()
Repeat
Delay(10)
Chrono+10
ForEver
EndProcedure
;{/ Génération du Visuel
OpenWindow(0, 0, 0, 180, 150,"Droopy",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
LoadFont(0,"Arial",26)
CreateGadgetList(WindowID(0))
Frame3DGadget(#Frame,10,10,160,60,"Chronomètre")
TextGadget(#Chrono, 20, 25 , 140, 40, "00:00:00",#PB_Text_Center)
SetGadgetFont(#Chrono,FontID(0))
ButtonGadget(#Start_Pause, 10, 75, 160, 20, "Start / Pause")
ButtonGadget(#Reset_Intermediaire, 10, 100, 160, 20, "Reset / Tps intermédiaire")
CreateStatusBar(#Status,WindowID(0))
StatusBarText(#Status,0," Chronomètre Arrêté")
;}
IdChrono=CreateThread(@Chronometre(),0)
PauseThread(IdChrono)
IdAffichage=CreateThread(@AffichageChrono(),0)
;{/ Gestion des évènements
Repeat
Event=WaitWindowEvent()
If Event=#PB_Event_Gadget
If EventType()=#PB_EventType_LeftClick
Select EventGadget()
Case #Start_Pause
;/ Si le chrono n'est pas en marche
If Start=0
Start=1
ResumeThread(IdChrono) ;/ On le démarre
StatusBarText(#Status,0," Chronomètre Démarré")
Else
;/ Si on presse Start pendant l'affichage d'un temps intermédiaire on relance l'affichage
If TpsIntermediaire=1
ResumeThread(IdAffichage)
TpsIntermediaire=0
Else
;/ Sinon on met le chrono en pause
Start=0
PauseThread(IdChrono)
StatusBarText(#Status,0," Chronomètre en Pause")
EndIf
EndIf
Case #Reset_Intermediaire
;/ Si le chrono est arrêté on met le chrono à zéro
If Start=0
Chrono=0
StatusBarText(#Status,0," Remise à zéro du Chronomètre")
Else
;/ Le Chrono est démarré --> On bloque l'affichage
If TpsIntermediaire=0
PauseThread(IdAffichage)
TpsIntermediaire=1
EndIf
;/ Puis on affiche un résultat intermédiaire
ms=(Chrono%1000)/10
Temp.s=Str(ms)
If ms<10
Temp.s="0"+Temp
EndIf
SetGadgetText(#Chrono,FormatDate("%ii:%ss",Chrono/1000)+":"+Temp)
StatusBarText(#Status,0," Affichage d'un temps intermédiaire")
EndIf
EndSelect
EndIf
EndIf
Until Event=#PB_Event_CloseWindow
;}
Publié : sam. 04/août/2007 14:11
par ThoT
Sympa les codes que vous me donnez là!
Juste un truc qui me chiffone avec WaitWindowEvent(milliseconds) :
Admettons que je veuille un compteur seconde par seconde, je ferai donc un code du genre
Code : Tout sélectionner
repeat
Event = WaitWindowEvent(1000)
chrono = chrono + 1
afficher_chrono()
until Event=#PB_Event_CloseWindow
Ca devrait declencher toutes les 1000 ms (soit toutes les secondes) l'incrementation de 1 de la variable "chrono" et son affichage par la procedure "afficher_chrono()".
Mais l'incrementation et l'affichage prenent un certain temps alors est-ce que j'aurai bien des secondes de 1000ms ou est-ce qu'elles feront 1000ms + le temps de realiser les actions?
Publié : mer. 08/août/2007 21:39
par ThoT
Pas de reponse ? Personne ne sait ?!

Publié : mer. 08/août/2007 22:08
par Octavius
Je suis pas un expert mais je pense que cette dernière méthode est imprécise.
Si je devais faire un chrono précis sans me casser la tête j'utiliserais la fonction ElapsedMilliseconds()
Une action (par exemple cliquer sur un bouton) déclencherait le chrono et tu aurais :
Et à chaque passage dans la boucle principale de ton programme tu affiches le temps écoulé :
Code : Tout sélectionner
Time=ElapsedMilliseconds()-TimeStart
SetGadgetText(#affichage_chrono,Str(Time))
D'après l'aide de PB cette fonction est assez précise, elle dépend de l'horloge de l'ordinateur directement je crois. Ton gadget #affichage_chrono ça peut être un StringGadget.
Avec un peu de travail sur le nombre Time, tu pourras différencier les millisecondes, les secondes et les minutes dans des variables différentes. (à condition de savoir manipuler la division et la fonction valeur entière)