Timer / Minuterie

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
ThoT
Messages : 33
Inscription : mar. 20/mars/2007 17:51

Timer / Minuterie

Message 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 :lol:
Avatar de l’utilisateur
Flype
Messages : 2431
Inscription : jeu. 29/janv./2004 0:26
Localisation : Nantes

Message 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

:wink:
Image
Avatar de l’utilisateur
Flype
Messages : 2431
Inscription : jeu. 29/janv./2004 0:26
Localisation : Nantes

Message 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.
Dernière modification par Flype le ven. 03/août/2007 20:36, modifié 1 fois.
Image
Avatar de l’utilisateur
Droopy
Messages : 1151
Inscription : lun. 19/juil./2004 22:31

Message 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)
Avatar de l’utilisateur
Flype
Messages : 2431
Inscription : jeu. 29/janv./2004 0:26
Localisation : Nantes

Message par Flype »

mais attention, les threads engendrent une programmation plus délicate.
Image
ThoT
Messages : 33
Inscription : mar. 20/mars/2007 17:51

Message 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?
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Message 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 !! :D
Avatar de l’utilisateur
Flype
Messages : 2431
Inscription : jeu. 29/janv./2004 0:26
Localisation : Nantes

Message 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).
Image
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Message par Backup »

Flype a écrit : WaitWindowEvent(MilliSecondes) peut suffir dans beaucoup de cas..
8O 8O j'avais jamais fais gaffe a cette particularité de cette fonction ! 8O

ce parametre "MilliSecondes" il n'existe que depuis la V4.10 non ? 8O
Avatar de l’utilisateur
Flype
Messages : 2431
Inscription : jeu. 29/janv./2004 0:26
Localisation : Nantes

Message par Flype »

depuis la 4.0 mon cher 8) çà fait un petit moment donc.
Image
Avatar de l’utilisateur
Droopy
Messages : 1151
Inscription : lun. 19/juil./2004 22:31

Message 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 
;}
ThoT
Messages : 33
Inscription : mar. 20/mars/2007 17:51

Message 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?
ThoT
Messages : 33
Inscription : mar. 20/mars/2007 17:51

Message par ThoT »

Pas de reponse ? Personne ne sait ?! 8O
Octavius
Messages : 312
Inscription : jeu. 26/juil./2007 12:10

Message 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 :

Code : Tout sélectionner

TimeStart=ElapsedMilliseconds()
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)
Répondre