Page 1 sur 1

Thread, WindowsTimer et Multi-fenêtres : je ne comprend pas

Publié : lun. 19/déc./2011 16:03
par Golfy
Le code suivant doit être compilé en mode Thread. Pour autant, il ne fait pas ce que je veux du tout !
Il devrait toutes les 5 secondes afficher une sous-fenêtre avec un comptage jusqu'à 10.

1) toutes les 5 secondes il devrait lancer le thread (grâce à AddWindowTimer) : rien
2) si je lance "manuellement" (clique barre menu) le thread, il n'affiche pas de valeur dans la "sous-fenêtre" : pourquoi ?

Code : Tout sélectionner

Enumeration
	#Obj_Window0
	#Obj_Window1
	#Obj_String0
	#Obj_String1
EndEnumeration
Global d

Procedure Counter(*Valeur)
	If OpenWindow(#Obj_Window1,150, 55,100,25,"Thread",#PB_Window_Tool,WindowID(#Obj_Window0))
		StringGadget(#Obj_String1,2,2,96,21,"Cnt")
		Delay(100)
		For t = 1 To 10
			SetGadgetText(#Obj_String1,Str(t)+"/100")
			Debug t
			Delay (200)  ; 10*200 = 2000mS = 2s
		Next t
		d = Date()
	EndIf
EndProcedure


If OpenWindow(#Obj_Window0,150,10,200,25,"Main")
	StringGadget(#Obj_String0,2,2,196,21,"Hello")
	AddWindowTimer(#Obj_Window0, 100, 5*1000)  ; 5 secondes
	d = Date()
	;
	Repeat
		EventID = WaitWindowEvent(20)
		If EventID <> 15
			Debug EventID
		EndIf
		If EventID = 674
			CreateThread(@Counter(),1)
		EndIf
		
			SetGadgetText(#Obj_String0,FormatDate("%hh:%ii:%ss",Date()-d))
			If EventID = #PB_Event_Timer
				Debug "Timer"
				CreateThread(@Counter(),1)
			EndIf
	Until EventID = #PB_Event_CloseWindow
	CloseWindow(#Obj_Window0)	
EndIf

Re: Thread, WindowsTimer et Multi-fenêtres : je ne comprend

Publié : lun. 19/déc./2011 17:19
par Golfy
Pour le point (2), il semble que le Gadget soit en cause :
- avec un TextGadget, la mise à jour s'affiche bien
- avec le stringGadget, un clic dans le Gadget régulier montre une progression... je ne sais pas pourquoi ce n'est pas plus dynamique mais bon... :?

Re: Thread, WindowsTimer et Multi-fenêtres : je ne comprend

Publié : lun. 19/déc./2011 19:36
par Mesa
ça fonctionne sur mon XP à part peut-être la destruction du thread.

De plus je confirme que le stringgadget a un problème.

Code : Tout sélectionner

Enumeration
   #Obj_Window0
   #Obj_Window1
   #Obj_String0
   #Obj_String1
EndEnumeration
Global d
Global le_Thread

Procedure Counter(*Valeur)
   ;If OpenWindow(#Obj_Window1,150, 55,100,25,"Thread",#PB_Window_Tool,WindowID(#Obj_Window0))
     If OpenWindow(#Obj_Window1,150, 55,100,25,"Thread", #PB_Window_Tool, WindowID(#Obj_Window0))     
       
       OldGadgetList = UseGadgetList(WindowID(#Obj_Window1)) ; Creation d'une GadgetList et sauvegarde l'ancienne GadgetList
      ;StringGadget(#Obj_String1,2,2,96,21,"Cnt")
       TextGadget(#Obj_String1,2,2,96,21,"Cnt")
       SetGadgetColor(#Obj_String1, #PB_Gadget_BackColor, $FFFFFF)
    
      Delay(100)
      For t = 1 To 10
         SetGadgetText(#Obj_String1,Str(t)+"/100")
         Debug t
         Delay (200)  ; 10*200 = 2000mS = 2s
      Next t
      ;d = Date()
    EndIf
    
    CloseWindow(#Obj_Window1)
    KillThread(le_Thread)
EndProcedure


If OpenWindow(#Obj_Window0,150,10,200,25,"Main")
  StringGadget(#Obj_String0,2,2,196,21,"Hello")
    AddWindowTimer(#Obj_Window0, 100, 1*1000)  ; 1 seconde
    AddWindowTimer(#Obj_Window0, 500, 5*1000)  ; 5 secondes
   d = Date()
   
   Repeat
     
     Event = WaitWindowEvent()
          
      If Event = #PB_Event_Timer And EventTimer() = 100
        SetGadgetText(#Obj_String0,FormatDate("%hh:%ii:%ss",Date()-d))
      EndIf
     
      If Event = #PB_Event_Timer And EventTimer() = 500
        d = Date()
        le_Thread=CreateThread(@Counter(),1)
      EndIf  
     
     

    Until EventID = #PB_Event_CloseWindow
    KillThread(le_Thread)
   CloseWindow(#Obj_Window0)   
EndIf
Mesa.

Re: Thread, WindowsTimer et Multi-fenêtres : je ne comprend

Publié : lun. 19/déc./2011 23:23
par Golfy
Oui, effectivement : je ne savais pas qu'il était nécessaire d'utiliser UseGadgetList() :
D'autre part, il faut fermer la ressource Window APRES avoir tué le thread, sous peine que le message suivant s'affiche dans le débogueur : il n'y a pas de GadgetList.....

Code : Tout sélectionner

Enumeration
   #Obj_Window0
   #Obj_Window1
   #Obj_String0
   #Obj_String1
EndEnumeration
Global d
Global le_Thread

Procedure Counter(*Valeur)
   ;If OpenWindow(#Obj_Window1,150, 55,100,25,"Thread",#PB_Window_Tool,WindowID(#Obj_Window0))
     If OpenWindow(#Obj_Window1,150, 55,100,25,"Thread", #PB_Window_Tool, WindowID(#Obj_Window0))     
       
       OldGadgetList = UseGadgetList(WindowID(#Obj_Window1)) ; Creation d'une GadgetList et sauvegarde l'ancienne GadgetList
      ;StringGadget(#Obj_String1,2,2,96,21,"Cnt")
       TextGadget(#Obj_String1,2,2,96,21,"Cnt")
       SetGadgetColor(#Obj_String1, #PB_Gadget_BackColor, $FFFFFF)
    
      Delay(100)
      For t = 1 To 10
         SetGadgetText(#Obj_String1,Str(t)+"/100")
         Debug t
         Delay (200)  ; 10*200 = 2000mS = 2s
      Next t
      ;d = Date()
    EndIf
    
    KillThread(le_Thread)
    CloseWindow(#Obj_Window1)
EndProcedure


If OpenWindow(#Obj_Window0,150,10,200,25,"Main")
  StringGadget(#Obj_String0,2,2,196,21,"Hello")
    AddWindowTimer(#Obj_Window0, 100, 1*1000)  ; 1 seconde
    AddWindowTimer(#Obj_Window0, 500, 5*1000)  ; 5 secondes
   d = Date()
   
   Repeat
     
     Event = WaitWindowEvent()
          
      If Event = #PB_Event_Timer And EventTimer() = 100
        SetGadgetText(#Obj_String0,FormatDate("%hh:%ii:%ss",Date()-d))
      EndIf
     
      If Event = #PB_Event_Timer And EventTimer() = 500
        d = Date()
        le_Thread=CreateThread(@Counter(),1)
      EndIf  
     
    Until EventID = #PB_Event_CloseWindow
    KillThread(le_Thread)
   CloseWindow(#Obj_Window0)   
EndIf

Re: Thread, WindowsTimer et Multi-fenêtres : je ne comprend

Publié : mar. 20/déc./2011 9:49
par Mesa
Un tout petit bug ici, il faut remplacer Until EventID= #PB_Event_CloseWindow par Until Event= #PB_Event_CloseWindow



Il existe une façon de faire sans Thread qui marche aussi bien et qui accélère un peu l'application.

Code : Tout sélectionner

Enumeration
   #Obj_Window0
   #Obj_Window1
   #Obj_String0
   #Obj_String1
EndEnumeration
Global d


Procedure Counter()
      HideWindow(#Obj_Window1, 0)
      Delay(100)
      For t = 1 To 10
        SetGadgetText(#Obj_String1,Str(t)+"/100")
         Debug t
         Delay (200)  ; 10*200 = 2000mS = 2s
      Next t
      
      HideWindow(#Obj_Window1, 1)
      
EndProcedure


If OpenWindow(#Obj_Window0,150,10,200,25,"Main")
    StringGadget(#Obj_String0,2,2,196,21,"Hello")
    AddWindowTimer(#Obj_Window0, 100, 1*1000)  ; 1 seconde
    AddWindowTimer(#Obj_Window0, 500, 5*1000)  ; 5 secondes
    d = Date()
    
     OpenWindow(#Obj_Window1,150, 55,100,25,"Thread", #PB_Window_Tool, WindowID(#Obj_Window0))     
       TextGadget(#Obj_String1,2,2,96,21,"Cnt")
       SetGadgetColor(#Obj_String1, #PB_Gadget_BackColor, $FFFFFF)
       HideWindow(#Obj_Window1, 1) 
   
   Repeat
     
     Event = WaitWindowEvent()
         
      If Event = #PB_Event_Timer And EventTimer() = 100
        SetGadgetText(#Obj_String0,FormatDate("%hh:%ii:%ss",Date()-d))
      EndIf
     
      If Event = #PB_Event_Timer And EventTimer() = 500
        d = Date()
        Counter()
      EndIf 
     
    Until Event= #PB_Event_CloseWindow
   
EndIf
Mesa.

Re: Thread, WindowsTimer et Multi-fenêtres : je ne comprend

Publié : jeu. 22/mars/2012 15:34
par Golfy
Avec le code ci-dessous, il y a plusieurs choses que je ne comprends pas :
1) pourquoi -- quand le thread est actif -- le déplacement de la fenêtre principal fige et n'affiche plus rien ?
2) pourquoi l'eventtimer() de 5 secondes ne marche pas tout le temps ?
3) pourquoi la documentation recommande de gérer les évènements dans chaque thread (http://www.purebasic.com/french/documen ... event.html) ?

Bref, un petit exemple vite fait de Fred ou Freak pourrait m'éclairer et apparaître dans la documentation officielle, je suis certain que cela rendrait service à tous !

Code : Tout sélectionner

Enumeration
   #Obj_Window0
   #Obj_Window1
   #Obj_String0
   #Obj_String1
EndEnumeration
Global d

Procedure Counter(*Valeur)
	If *Valeur > 5
		Title$="Thread Timeout"
		Y = 60
	Else
		Title$="Thread Timer"
		Y = 120
	EndIf
	
	WinThread = OpenWindow(#PB_Any,150, Y,100,25,Title$,#PB_Window_Tool,WindowID(#Obj_Window0))
  TextGadget(#Obj_String1,2,2,96,21,"Cnt")
  SetActiveWindow(#Obj_Window0)
  Delay(10)
  For t = 1 To *Valeur
   SetGadgetText(#Obj_String1,Str(t)+"/"+Str(*Valeur))
   Debug t
   tz = ElapsedMilliseconds()
   Repeat
   Until ElapsedMilliseconds()-tz > 500
  Next t
  CloseWindow(WinThread)
EndProcedure


If OpenWindow(#Obj_Window0,150,10,200,25,"Main")
   StringGadget(#Obj_String0,2,2,196,21,"Hello")
   Minuteur = AddWindowTimer(#Obj_Window0, 100, 5*1000)  ; 5 secondes
   d = Date()
   Repeat
      EventID = WaitWindowEvent(20)
      If EventID = #PB_Event_Timer And EventTimer() = Minuteur
      ; Lance le thread avec le paramètre 3 toute les 5 secondes
        Debug "Timer"
        CreateThread(@Counter(),3)
      EndIf
			If Date()-d > 10
      ; Lance le thread avec le paramètre 10 toute les 10 secondes
      	d = Date()
        CreateThread(@Counter(),10)
      EndIf
      SetGadgetText(#Obj_String0,FormatDate("%hh:%ii:%ss",Date()-d))
    Until EventID = #PB_Event_CloseWindow
   CloseWindow(#Obj_Window0)   
EndIf

Re: Thread, WindowsTimer et Multi-fenêtres : je ne comprend

Publié : jeu. 22/mars/2012 19:20
par nico
1) pourquoi -- quand le thread est actif -- le déplacement de la fenêtre principal fige et n'affiche plus rien ?
Parce que une fenêtre ne peut exister sans gestion des évènements
Or dans ton thread, tu ne gère pas de boucle, essayes de rajouter un gadget dans ce thread, tu vas comprendre!
2) pourquoi l'eventtimer() de 5 secondes ne marche pas tout le temps ?
Chez moi, il ne marche pas du tout sauf si je bouge la fenêtre
En plus, il y a une erreur faut remplacer Minuteur = AddWindowTimer(#Obj_Window0, 100, 5*1000) par AddWindowTimer(#Obj_Window0, # Minuteur, 5*1000)
et mettre If EventID = #PB_Event_Timer And EventTimer() = #Minuteur (voir l'aide)
Tu as mis un SetGadgetText(#Obj_String0,FormatDate("%hh:%ii:%ss",Date()-d)) en dehors de tout traitement d'un évènement particulier ce qui pose problème
car c'est un sendmessage_(...) alors que les messages timer sont des postmessage_(...)
ce qui signifie que les messages envoyés par sendmessage sont prioritaires et passe devant les postmessage et comme ça ne s'arrête jamais
le message Timer n'est jamais traiter par la boucle, ceci expliquant cela
3) pourquoi la documentation recommande de gérer les évènements dans chaque thread (http://www.purebasic.com/french/documen ... event.html) ?
La documentation ne recommande pas de traiter la gestion des messages dans chaque thread, elle indique qu'il faut le faire car il est impossible de le faire autrement!

Re: Thread, WindowsTimer et Multi-fenêtres : je ne comprend

Publié : jeu. 22/mars/2012 19:27
par graph100
j'ai fait un code qui devrait faire la même chose que le tiens, on peut déplacer les fenetres, et il fonctionne normalement.
J'ai ajouter une liste pour checker que les thread sont bien tous terminés à la fin. (luxe inutile pour un tel code, mais néanmoins intéressant à voir je pense)

Code : Tout sélectionner


;{ init

Structure thread_id
	thread_id.l
	
	valeur.l
EndStructure



Global IS_end.b = 0

compteur = 0



Global NewList thread_id.thread_id()


;}



Procedure Thread_Compteur(*id.thread_id)
	If *id\valeur > 5
		Title$="Thread Timeout"
		Y = 60
	Else
		Title$="Thread Timer"
		Y = 120
	EndIf
	
	thread_window = OpenWindow(#PB_Any, 200, Y, 200, 25, Title$, #PB_Window_Tool)
	
	If thread_window
		thread_textgadget = TextGadget(#PB_Any, 5, 5, 90, 20, "", #PB_Text_Border)
		
	Else
		ProcedureReturn 
	EndIf
	
	time = ElapsedMilliseconds()
	
	Repeat
		event = WaitWindowEvent(50)
		
		SetGadgetText(thread_textgadget, Str(ElapsedMilliseconds() - time) + "ms")
		
		
		If ElapsedMilliseconds() - time > *id\valeur * 1000
			event = #PB_Event_CloseWindow
		EndIf
		
	Until event = #PB_Event_CloseWindow Or IS_end
	
	If IS_end = 0
		ChangeCurrentElement(thread_id(), *id)
		DeleteElement(thread_id())
	EndIf
	
	CloseWindow(thread_window)
	
EndProcedure



If OpenWindow(0, 420, 100, 200, 30, "Test", #PB_Window_SystemMenu)
	TextGadget(0, 5, 5, 190, 20, "", #PB_Text_Border)
	
	AddWindowTimer(0, 0, 1000) ; ajoute un timer à la fenetre 0, tick toutes les 1 sec
Else
	MessageRequester("Erreur", "Impossible de lancer la fenetre principale")
EndIf




Repeat
	event = WaitWindowEvent()
	
	
	If event = #PB_Event_Timer And EventTimer() = 0
		compteur + 1
		
		SetGadgetText(0, Str(compteur) + "s")
		
		If compteur = 5
			*current.thread_id = AddElement(thread_id())
			
			*current\valeur = 3
			*current\thread_id = CreateThread(@Thread_Compteur(), *current)
			
		ElseIf compteur = 10
			*current.thread_id = AddElement(thread_id())
			
			*current\valeur = 10
			*current\thread_id = CreateThread(@Thread_Compteur(), *current)
			
			
			compteur = 0
		EndIf
	EndIf
	
	
Until event = #PB_Event_CloseWindow

IS_end = #True

ForEach thread_id()
	*current.thread_id = @thread_id()
	WaitThread(*current\thread_id)
Next

End

Re: Thread, WindowsTimer et Multi-fenêtres : je ne comprend

Publié : jeu. 22/mars/2012 20:24
par Golfy
nico a écrit :
1) pourquoi -- quand le thread est actif -- le déplacement de la fenêtre principal fige et n'affiche plus rien ?
Parce que une fenêtre ne peut exister sans gestion des évènements
Or dans ton thread, tu ne gère pas de boucle, essayes de rajouter un gadget dans ce thread, tu vas comprendre!
OK, en ajoutant un WaitWindowEvent(5) dans la boucle du thread, je peux déplacer la fenêtre principal... ce qui règle aussi le point (3) :)
2) pourquoi l'eventtimer() de 5 secondes ne marche pas tout le temps ?
Chez moi, il ne marche pas du tout sauf si je bouge la fenêtre
En plus, il y a une erreur faut remplacer Minuteur = AddWindowTimer(#Obj_Window0, 100, 5*1000) par AddWindowTimer(#Obj_Window0, # Minuteur, 5*1000)
et mettre If EventID = #PB_Event_Timer And EventTimer() = #Minuteur (voir l'aide)
Tu as mis un SetGadgetText(#Obj_String0,FormatDate("%hh:%ii:%ss",Date()-d)) en dehors de tout traitement d'un évènement particulier ce qui pose problème
car c'est un sendmessage_(...) alors que les messages timer sont des postmessage_(...)
ce qui signifie que les messages envoyés par sendmessage sont prioritaires et passe devant les postmessage et comme ça ne s'arrête jamais
le message Timer n'est jamais traiter par la boucle, ceci expliquant cela
Là par contre, c'est pas clair :(
En ajoutant le WaitWindowEvent() dans le thread, je n'ai plus de problème pour le SetGadgetText (ni pour les déplacements de fenêtre) : l'aspect sendmessage et postmessage est donc contourné (ceci étant, si tu as des liens pour me permettre de mieux comprendre d'où viennent ces notions, je suis preneur).
Toutefois, la partie Timer ne fonctionne pas et le #Minuteur n'est indiqué nul part dans la doc (http://www.purebasic.com/french/documen ... timer.html).

je dois mettre

Code : Tout sélectionner

AddWindowTimer(#Obj_Window0, 100, 5*1000)
et dans mon test de validité

Code : Tout sélectionner

If EventID = #PB_Event_Timer And EventTimer() = 100
Malgré cela, pas de timer (et même, une fois j'ai eu le timer et quelques sec. après j'ai "le #Gadget spécifié n'est pas initialisé" sur la ligne EventID = WaitWindowEvent(20) de la boucle principale :x

En tout cas, merci pour les explications :wink: : je sens que je passe pas loin mais je ne comprend pas encore le fonctionnement :oops: Je programme en newbie et du coup, je ne sais pas comment gérer correctement mes évènements ! j'aimerai trouver un schéma qui montre la pile d'évènement et quand et comment ils sont dépilés...
Un peu comme ça http://openbook.galileocomputing.de/jav ... 14_039.png ou http://tripamort.free.fr/?q=node/6

Re: Thread, WindowsTimer et Multi-fenêtres : je ne comprend

Publié : jeu. 22/mars/2012 20:39
par nico
En ajoutant le WaitWindowEvent() dans le thread, je n'ai plus de problème pour le SetGadgetText (ni pour les déplacements de fenêtre) : l'aspect sendmessage et postmessage est donc contourné
Malgré cela, pas de timer
Je ne comprend pas, tu dis que ça marche et ensuite tu dis que ça ne marche pas, c'est pas clair!
Le problème du SetGadgetText n'affecte que le timer!

En tout cas chez moi, même avec un waitwindowevent, le timer de 5 seconde ne fonctionne pas, j'en revient à mon explication.
Toutefois, la partie Timer ne fonctionne pas et le #Minuteur n'est indiqué nul part dans la doc (http://www.purebasic.com/french/documen ... timer.html).
#Minuteur est juste une constante, tu peux mettre un chiffre mais c'est mieux avec, le code est plus clair comme avec un openwindow
En tout cas, merci pour les explications : je sens que je passe pas loin mais je ne comprend pas encore le fonctionnement Je programme en newbie et du coup, je ne sais pas comment gérer correctement mes évènements ! j'aimerai trouver un schéma qui montre la pile d'évènement et quand et comment ils sont dépilés...
Purebasic simplifie tellement les choses, qu'il est impossible de comprendre ce qui se passe derrière les instructions et comment fonctionne une simple fenêtre, tout passe par la compréhension des API Window, la gestion des messages, le fonctionnement de la boucle etc...
Je m'y suis intéressé très tôt et j'ai quelques livres sur le sujet.