Question de propreté de code... et de fonctionnement

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Golfy
Messages : 423
Inscription : mer. 25/août/2004 15:14
Localisation : Grenoble
Contact :

Question de propreté de code... et de fonctionnement

Message par Golfy »

Pour mon programme domotique, je souhaite avoir une fenêtre principale avec plusieurs gadgets (de l'ordre d'une centaine) : des graphes, des champs éditables, des boutons reflétant l'état des lampes, etc.

Je veux aussi utiliser un listicongadget pour indiquer les évènements à venir (allumage de lampe à 7h, volet roulant XX à 7h15,...) et comme je veux pouvoir changer cette programmation, un double-clic sur cette liste doit faire quelque chose : idéalement, éditer le champ sélectionné (mais la programmation employée sur les différents post me rebute un peu par la complexité et surtout le risque de non-compatibilité Win/linux) ou bien ouvrir une boite de dialogue.
Là, ça devient un peu moche car soit je rajoute mes constantes dans mon encart ENUM (ça commence à faire des constantes nombreuses), soit je peux utiliser des valeurs locales à ma procédure d'édition...
Enfin, durant mon édition, je souhaite que ce ne soit pas bloquant pour l'ensemble du programme (qui effectue des relevés de température par exemple, ou stocke les messages en provenance du BUS) : comment dois-je gérer cela ?

Actuellement, j'utilise des eventtimer

Code : Tout sélectionner

				If EventID=#PB_Event_Timer
					Select EventTimer()
						Case 100
							WriteTempFile()
							GraphTemp()
						Case 101
							VelbusBPCalc()
						Case 102
							ClearOldMsg(4)
					EndSelect
				EndIf
Bref, une vision du bon fonctionnement m'intéresse pour ne pas être bloquant comme en automatisme :)

Pour le moment, j'ai une procédure qui est lancée en cas de double-clic pour afficher la fenêtre d'édition (très basique) :

Code : Tout sélectionner

Procedure EditEvent(ligne)
	OpenWindow(#EE_Window,50,50,200,120,"Editer événement",#PB_Window_ScreenCentered|#PB_Window_Normal)
	StringGadget(#EE_StrHM, 100, 10, 80, 18, GetGadgetItemText(#Editor_Reveil,ligne,2))
	StringGadget(#EE_StrDay, 100, 30, 80, 18, GetGadgetItemText(#Editor_Reveil,ligne,1))
	StringGadget(#EE_StrAdr, 100, 50, 80, 18, GetGadgetItemText(#Editor_Reveil,ligne,4))
	StringGadget(#EE_StrMod, 100, 70, 80, 18, GetGadgetItemText(#Editor_Reveil,ligne,5))
	ButtonGadget(#EE_ButtonOK,70,90,80,18,"OK")
EndProcedure

Puis dans ma boucle principale, je surveille le bouton

Code : Tout sélectionner

						Case #EE_ButtonOK
							ligne = GetGadgetState(#Editor_Reveil)
							SetGadgetItemText(#Editor_Reveil,ligne,GetGadgetText(#EE_StrHM),2)
							SetGadgetItemText(#Editor_Reveil,ligne,GetGadgetText(#EE_StrDay),1)
							SetGadgetItemText(#Editor_Reveil,ligne,GetGadgetText(#EE_StrAdr),4)
							SetGadgetItemText(#Editor_Reveil,ligne,GetGadgetText(#EE_StrMod),5)
							
							CloseWindow(#EE_Window)
					EndSelect
Ca me paraît très "crade" comme structure de codage mais je ne sais pas s'il y a d'autres moyens plus d'en "l'état de l'Art" :(

Merci
Purebasic 5.30 full sous Windows XP (x86) et Win7 (64 bits), Linux Debian. Orientation réseaux, domotique
http://golfy.olympe.in/Teo-Tea/
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Question de propreté de code... et de fonctionnement

Message par graph100 »

oula oula !!

Dans un prog de robotique, ne pas être bloquant et rester à l'écoute de ton interface est super important. (mais je crois que tu l'as dis ^^)
Pour ce que j'avais employé avec un prog communiquant avec un automate, j'avais utilisé les threads.

Ca a peut etre l'air compliqué comme ca, mais une fois que tu as compris c'est bon.

Un thread te lance une procedure qui va tourner en parallèle avec ton prog. Il faut bien sur gérer l'arret de cette procédure et prendre quelques précaution, mais je pense que c'est une approche viable.

Pour ce que tu décris avec tout tes gadgets, franchement si t'en as vraiment une centaine, je sais pas si ton interface est viable !! Utilise peut etre la création dynamique (#PB_Any) et gère les dynamiquements .., enfin ya pas de code je vois pas trop)

je te balance un code simple qui est en thread, j'ai fait des prog plus complexe mais trop gros (ou des projets complet) pour être posté et compris simplement.

Code : Tout sélectionner

Global IS_pointille.b = #False

Procedure Pointille(bla)
	a = 0
	
	Repeat
		SetGadgetText(0, LSet("Attente ", 8 + a, "."))
		
		a + 1
		If a = 5 : a = 0 : EndIf
		
		Delay(500)
	Until IS_pointille = #True
	
	SetGadgetText(0, "Le programme est fermé")
EndProcedure

Procedure LancementProgramme(*adresse_nom_prog)
	id_prog = RunProgram(PeekS(*adresse_nom_prog), "", "", #PB_Program_Open)
	
	If id_prog
		WaitProgram(id_prog)
	EndIf
	
EndProcedure


If OpenWindow(0, 0, 0, 140, 40, "blabla", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
	TextGadget(0, 10, 10, 120, 20, "Attente")
EndIf


; lancement des pointillés d'attente
thread_pointille = CreateThread(@Pointille(), 0)

; lancement du thread de lancement du programme
; prog.s = "C:\Windows\System32\calc.exe"
prog.s = "calc.exe"
thread_program = CreateThread(@LancementProgramme(), @prog)

Repeat
	event = WaitWindowEvent(100)
	
	If IsThread(thread_program) = 0
		IS_pointille = #True
	EndIf
	
Until event = #PB_Event_CloseWindow



End
et désolé je n'ai pas le temps de te bidouiller un code plus ciblé ><
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Mesa
Messages : 1126
Inscription : mer. 14/sept./2011 16:59

Re: Question de propreté de code... et de fonctionnement

Message par Mesa »

Je pense aussi qu'il faut un thread pour les mesures et affichage domotique.

Quelque chose comme ça :

Code : Tout sélectionner

Enumeration
  #Fen
  #Text1
  #Text2
  #Text3
  #image
  #imagegadget
  #Listicongadget
  EndEnumeration 



Procedure Mesure_affichage(Valeur)
  ;Debug Valeur
  Repeat
    StartDrawing(ImageOutput(#image))
    Box(0, 0, 200, 200, RGB(255, 255, 255))
    StopDrawing() 
    
    For Width = 1 To 180 Step 5
      StartDrawing(ImageOutput(#image))
      
      Line(10, 10, Width, 180, RGB(Random(255), Random(255), Random(255)))
      
      
      StopDrawing() 
      
      SetGadgetState(#imagegadget,ImageID(#image))
      Delay(50)
    Next Width
    StartDrawing(ImageOutput(#image))
    Box(0, 0, 200, 200, RGB(255, 255, 255))
    StopDrawing()
    
    For Width = 180 To 1 Step -5
      StartDrawing(ImageOutput(#image))
      
      Line(10, 10, Width, 180, RGB(Random(255), Random(255), Random(255)))
      
      StopDrawing() 
      SetGadgetState(#imagegadget,ImageID(#image))
      Delay(50)
    Next Width 
  ForEver
EndProcedure

Procedure Gestion_listicongadget()
  saisie$=InputRequester("Nouveau","Entrer le nouveau texte","Entrer le nouveau texte")
  SetGadgetItemText(#Listicongadget, GetGadgetState(#Listicongadget), saisie$)
  
EndProcedure



If OpenWindow(#Fen, 0, 0, 600, 400, "2DDrawing Example", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  CreateImage(#image, 200, 200)
  ImageGadget(#imagegadget, 10, 10, 200, 200, ImageID(#image))
  TextGadget(#Text1, 10, 210, 200, 60, "Ici le Thread qui fait des mesures domotiques + Affichage des mesures...")
  TextGadget(#Text2, 250,  10, 300, 20, "Evènement à venir...")
  ListIconGadget(#Listicongadget,  250,  35, 300, 170, "Colonne 1", 100)
  SetGadgetItemAttribute(#Listicongadget, #PB_Ignore,  #PB_ListIcon_ColumnWidth, 250,0)
  For i= 0 To 2          ; ajouter 4 éléments à chaque ligne des listes avec icônes
    AddGadgetItem(#Listicongadget, b, "Elément " +Str(i))
  Next i
  TextGadget(#Text3, 250,  210, 200, 60, "...Et pendant ce temps on peut changer des évènements : double-clic !")
  
  CreateThread(@Mesure_Affichage(), 100) ; Création du thread "mesure domotique et affichage"
  
  Repeat
    ;et pendant ce temps, la boucle gère le listicon (en même temps que les mesures et affichage)

    Event = WaitWindowEvent()
    If Event=#PB_Event_Gadget 
      If EventGadget()=#Listicongadget
                   Select EventType()
        ;              Case #PB_EventType_LeftClick        : Debug "Clic avec le bouton gauche de la souris"
        ;              Case #PB_EventType_RightClick       : Debug "Clic avec le bouton droit de la souris"
                     Case #PB_EventType_LeftDoubleClick  : Gestion_listicongadget()
                   EndSelect
        ;Gestion_listicongadget()
      EndIf
    EndIf
    
  Until Event = #PB_Event_CloseWindow
EndIf

Mesa.
Golfy
Messages : 423
Inscription : mer. 25/août/2004 15:14
Localisation : Grenoble
Contact :

Re: Question de propreté de code... et de fonctionnement

Message par Golfy »

Pour le moment, les threads ne fonctionnent pas (je dois avoir une lib qui pose problème ou bien c'est le passage 64bit/i86 qui pose problème.
Le code est ici :
http://golfy.free.fr/Velbus/Tea.pb

Les procédures Velbus (include)
http://golfy.free.fr/Velbus/Velbus_Teo-Tea.pb
Purebasic 5.30 full sous Windows XP (x86) et Win7 (64 bits), Linux Debian. Orientation réseaux, domotique
http://golfy.olympe.in/Teo-Tea/
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Question de propreté de code... et de fonctionnement

Message par graph100 »

quelques conseils rapide (je n'ai pas le temps de me pencher sur le code maintenant ;(- ) :
- utilise toujours le type integer .i pour les adresses et les pointeurs (passage 64/32 bits immédiat
- teste avec le paramètre "threadsafe" dans les options du compilateur
- vérifié ton code pour voir si tu n'as pas des occasions dans lesquelles une même ressource mémoire (variable, liste chainée, Array, map) est modifiée par plusieurs thread en même temps -> error memory access (et le prog principal est aussi un thread ^^)

si c'est le cas, tu peux : soit modifier ton approche en rendant les objets uniques par thread, soit bloquer l'access des ressources concernées par des mutex et sémaphore etc.. (voir aide)

Pour passer des paramètres aux threads il y a aussi des précautions à prendre (voir post suivant)
Mais pour communiquer facilement, utilise des flags globaux (une variable déclarée en global qui va te permettre de communiquer facilement entre thread)
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Répondre