Page 1 sur 1

Deux boucles évènementielles dont une en thread

Publié : jeu. 24/mai/2012 14:15
par falsam
Une idée aussi sotte que grenue (Comme cette expression). Est il correct d'avoir, pour une seule fenêtre, deux boucles évènementielles dont une en thread pour gérer les Evénements ?

Dans le code ci-dessous je souhaite que le "clic" sur le carré blanc, soit géré en thread et non pas dans la boucle principale.

Code : Tout sélectionner

EnableExplicit

Enumeration
  #Mainform
  #Canvas
  #Button
EndEnumeration

Procedure MonThread(Value)
  Protected EGadget.l, EType.l
  
  Repeat
    EGadget = EventGadget()
    EType = EventType()
    If EGadget And GadgetType(EGadget)=#PB_GadgetType_Canvas And EType=#PB_EventType_LeftClick   
      Debug "Clic"
    EndIf    
  ForEver 
EndProcedure

OpenWindow(#Mainform, 0, 0, 500, 400, "New Form")
CanvasGadget(#Canvas, 10, 20, 20, 20, #PB_Canvas_ClipMouse)
ButtonGadget(#Button, 10,50, 80, 20, "teste")

CreateThread(@MonThread(), 999)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_Gadget
      Select EventGadget()
      EndSelect
        
    Case #PB_Event_CloseWindow
      End
  EndSelect
  
ForEver

Re: Deux boucles évènementielles dont une en thread

Publié : jeu. 24/mai/2012 14:41
par Backup
pourquoi faire Simple , lorsqu'on peut compliquer .. :)

compare ton code avec celui-ci

que remarque tu ? ( niveau Résultat dans le Debug .. )

Code : Tout sélectionner

EnableExplicit

Enumeration
	#Mainform
	#Canvas
	#Button
EndEnumeration


OpenWindow(#Mainform, 0, 0, 500, 400, "New Form")
CanvasGadget(#Canvas, 10, 20, 20, 20, #PB_Canvas_ClipMouse)
ButtonGadget(#Button, 10,50, 80, 20, "teste")



Repeat
	Select WaitWindowEvent()
		Case #PB_Event_Gadget
		Select EventGadget()
			case #Canvas
			select EventType()
				case #PB_EventType_LeftClick   
				Debug "Clic"
			EndSelect
			case #Button
			debug "bouton"
		EndSelect
		
		Case #PB_Event_CloseWindow
		End
	EndSelect
	
ForEver

; EPB

allez , j’anticipe ta réponse

ton code renvoi plusieurs fois une réponse de Click !
parce que le Threads a le temps d'etre effectuer plein de fois pendant ton click

c'est quand meme bouffer beaucoup de ressources pour rien ..
et de plus , tu risque d'etre confronté a des problemes de double click du coup ...

en Programmation Basic , le mieux c'est de garder les differente possibilité pour ce qu'elles sont prévue ..

un Thread sert a executer un traitement en parralelle , ( un calcul , une progression quelquonque , traitement video, graphique etc ... )

les event Window , sont une liste qui se met a jour par Windows ( le system D'exploitation )

cette list se déroule dans le sens dans lequel les evenements arrive
bref , c'est synchrone

les threads , par définition ; sont Asynchrone ..

on ne mélange pas des choses synchrone et Asynchrone , sans risquer a un moment le Crash :)

bien sur on , peut toujours bidouiller, (et je suis le roi de la bidouille) ... mais c'est risqué :)

voila :)

Re: Deux boucles évènementielles dont une en thread

Publié : jeu. 24/mai/2012 14:44
par Ar-S
Je pense que c'est plus pour l'exemple que Falsam à mis ça. En revanche c'est vrai que l'exemple montre que le debug affiche 4 fois clic par clic.
Ce qui me gêne c'est que le thread tourne à l'infini.
J'ajouterai un flag (stop=1) pour pouvoir le stopper (via le clic droit).

Code : Tout sélectionner

Procedure MonThread(Value)
	Protected EGadget.l, EType.l, stop.b
	stop = 0
	Repeat
		EGadget = EventGadget()
		EType = EventType()
		If EGadget And GadgetType(EGadget)=#PB_GadgetType_Canvas And EType=#PB_EventType_LeftClick   
			Debug "Clic"
    ElseIf EGadget And GadgetType(EGadget)=#PB_GadgetType_Canvas And EType=#PB_EventType_RightClick
      stop = 1
    EndIf    
  Until stop = 1 
EndProcedure

Re: Deux boucles évènementielles dont une en thread

Publié : ven. 25/mai/2012 2:23
par falsam
Ar-S tu as raison. C'était juste pour l'exemple. Le but de ma demande est de pouvoir par exemple creer un gadget et de pouvoir gérer certains évènements de ce gadget sans une seule ligne de code dans le code principale.

Le mieux est de fournir un exemple pour résumé mes propos. le contenu de la ligne 1 à 70 aurait du être dans un fichier include ou une lib.

Code : Tout sélectionner

;-Private
Structure ExplorerBar
  IdPanel.l
  Height.i
  Reduce.b
EndStructure

Global *Adress.ExplorerBar

;Redimentionne un Explorerbar
Procedure __ResizeGadget(IdPanel)
  If *Adress\Reduce=#True
    ResizeGadget(IdPanel, #PB_Ignore, #PB_Ignore, #PB_Ignore, *Adress\Height) 
    *Adress\Reduce=#False
  Else
    ResizeGadget(IdPanel, #PB_Ignore, #PB_Ignore, #PB_Ignore, 30) 
    *Adress\Reduce=#True
  EndIf
EndProcedure

;Quel est l'ExplorerBar Actif ?
Procedure __GetActiveExplorerBar(Value)
  Protected EGadget.l, EType.l, IdCanvasData.l
  
  Repeat
    EGadget = EventGadget()
    EType = EventType()
    If EGadget And GadgetType(EGadget)=#PB_GadgetType_Canvas And EType=#PB_EventType_LeftClick
      If GetGadgetData(EGadget)<>IdCanvasData
        IdCanvasData=GetGadgetData(EGadget)
        *Adress.ExplorerBar = IdCanvasData
        __ResizeGadget(*Adress\IdPanel)
        IdCanvasData=0
      EndIf
    EndIf    
  ForEver 
EndProcedure

;- Public
Procedure CreateExplorerBar(Gadget, x, y, Width, Height, Text$)
  Protected IdGadget.l
  
  If Gadget=#PB_Any
    IdGadget=PanelGadget(Gadget, x, y, Width, Height)
  Else
    PanelGadget(Gadget, x, y, Width, Height)
  EndIf
  
  *Adress.ExplorerBar = AllocateMemory(SizeOf(ExplorerBar))
  InitializeStructure(*Adress, ExplorerBar)
  *Adress\IdPanel=IdGadget
  *Adress\Reduce=#False
  *Adress\Height=height
  
  IdGadget=CanvasGadget(#PB_Any, Width-25, 10, 15, 15)
  SetGadgetData(IdGadget, *Adress)
  SetGadgetAttribute(IdGadget, #PB_Canvas_Cursor, #PB_Cursor_Hand)
    
  StartDrawing(CanvasOutput(IdGadget))
  RoundBox(0,0,14,14,3,3, RGB(192, 192, 192))
  DrawingMode(#PB_2DDrawing_Outlined)
  RoundBox(0,0,14,14,3,3, RGB(0, 0, 0))
  StopDrawing()
EndProcedure


;Le Thread permet de connaitre l'ExploreBar actif
CreateThread(@__GetActiveExplorerBar(), 999)

;-Test 

EnableExplicit

Enumeration
  #Mainform
  #Canvas
  #Button
EndEnumeration

OpenWindow(#Mainform, 0, 0, 500, 400, "New Form")

CreateExplorerBar(#PB_Any, 10, 20, 200, 150, "Bar 1")
  StringGadget(#PB_Any, 10, 30, 80, 20, "")
  ButtonGadget(#PB_Any, 120, 90, 60, 20, "Button1")
  ButtonGadget(#PB_Any, 120, 115, 60, 20, "Button2")
CloseGadgetList()

CreateExplorerBar(#PB_Any, 10, 200, 200, 150, "Bar 2")
  StringGadget(#PB_Any, 10, 30, 80, 20, "")
  ButtonGadget(#PB_Any, 120, 90, 60, 20, "Button3")
  ButtonGadget(#PB_Any, 120, 115, 60, 20, "Button4")
CloseGadgetList()

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_Gadget
      Select EventGadget()
      EndSelect
        
    Case #PB_Event_CloseWindow
      End
  EndSelect
  
ForEver

Re: Deux boucles évènementielles dont une en thread

Publié : ven. 25/mai/2012 9:24
par Mesa
C'est intéressant.

Tu as 2 boucles infinies, celle de la fenêtre et celle du thread.
Reste à savoir comment purebasic, qui a été écrit en C++, je crois, gère les thread sur les processeurs multicores.

On peut penser qu'on gagne en vitesse de réponse du programme si le thread tourne sur un core pendant que la boucle principale tourne sur un autre, sinon on remplace une procédure par un thread.

Existe-til un moyen pour savoir quel thread tourne sur quel core ?

Mesa.

Re: Deux boucles évènementielles dont une en thread

Publié : ven. 25/mai/2012 11:02
par Le Soldat Inconnu
Cette solution me semble plus que très peu fiable.

Pourquoi ne pas faire appel à la procedure du thread (procedure sans la boucle) dans la boucle principal, plus simple et plus robuste

Re: Deux boucles évènementielles dont une en thread

Publié : sam. 26/mai/2012 13:23
par djes
Tu peux parfaitement utiliser une procédure pour traiter les évènements (c'est même la façon standard dans Windows), mais ça demande un peu d'expérience (bientôt!). Voir SetWindowCallback()

Re: Deux boucles évènementielles dont une en thread

Publié : sam. 26/mai/2012 13:45
par falsam
@Djes : Je n'utilise pas de SetWindowCallback pour rester dans une solution cross-platform.

@LSI : Dans l'exemple que je donne je souhaite que la gestion d'ouverture ou fermeture du panel soit transparente. Quand on utilise un TreeViewgadget, la gestion des noeuds (ouverture et fermeture) est transparente et je souhaite qu'il en soit de même pour mon exemple.