Thread and gadget creation

Just starting out? Need help? Post your questions and find answers here.
boddhi
Enthusiast
Enthusiast
Posts: 524
Joined: Mon Nov 15, 2010 9:53 pm

Thread and gadget creation

Post by boddhi »

Hi,

I've driving my brain crazy for the last 3-4 days trying to understand why some of my code isn't working.

Here's a purified functional adaptation, except that in the original code the more complex UI is created with the DialogXML lib and the procedure is called inside a thread. This procedure is exactly the same as the original. That's why I haven't translated the variable names, to avoid making mistakes.

Code: Select all

DebugLevel 5
;UsePNGImageEncoder()

Enumeration Fenetres
  #CGP_FENPRINCIPALE
EndEnumeration
Enumeration Gadgets
  #GAD_FP_ZD_GALERIE
  #GAD_FP_IMG_0
EndEnumeration
Enumeration Polices
  #POLICE
EndEnumeration
Enumeration Images
  #IMG_TEXTEEXEMPLE
EndEnumeration

Global.u HauteurPoliceSysteme

NomPolice.s=""
FichierPolice.s=""
#TEXTETEST="ABCDEFGH abcdefgh ÀCÉÏÔ àçéïô 012345 ?!€$+={([A"
#COUL_TEXTETITRE=#White
#COUL_FONDTEXTETITRE=#Red
#COUL_TEXTEEXEMPLE=#Black
#COUL_FONDTEXTEEXEMPLE=#White

CompteurGadget.u=0:HauteurImage.u=0:PositionY.u=4:HauteurTexte.u=0:LargeurTexte.u=0
Global FacteurEchelleX.f=DesktopScaledX(100)/100
Global FacteurEchelleY.f=DesktopScaledY(100)/100
;

#GAD_FP_IMG_POLICE=50

Procedure.u Fc_Affichage_ImagePolice(ArgFichier.s,ArgNomPolice.s,ArgStyle.u,ArgTexteComplement.s,ArgCompteur.u,ArgPositionY.l)
  Debug #PB_Compiler_Procedure+" (Fichier="+ArgFichier+",NomPolice="+ArgNomPolice+",TexteComplement="+ArgTexteComplement+",Compteur="+ArgCompteur+",PositionY="+ArgPositionY+")",5
  Protected.u PositionY,HauteurImage,LargeurTexte,HauteurTexte,NoGadget=#GAD_FP_IMG_POLICE+ArgCompteur,Style
  
  If RegisterFontFile(ArgFichier)
    If ArgStyle&1:Style=#PB_Font_Italic:EndIf        ; Italique
    If ArgStyle>>1&1:Style|#PB_Font_Underline:EndIf  ; Souligné
    If ArgStyle>>4&1:Style|#PB_Font_StrikeOut:EndIf  ; Barré
    If ArgStyle>>5&1:Style|#PB_Font_Bold:EndIf       ; Gras
    LoadFont(#POLICE,ArgNomPolice,24,Style)
    StartDrawing(WindowOutput(0))
    DrawingFont(FontID(#POLICE))
    LargeurTexte=TextWidth(#TEXTETEST):HauteurTexte=TextHeight(#TEXTETEST)
    StopDrawing()
    PositionY=HauteurTexte+8:HauteurImage=HauteurPoliceSysteme+8+PositionY
    If CreateImage(#IMG_TEXTEEXEMPLE,792*FacteurEchelleX,HauteurImage,32,#COUL_FONDTEXTEEXEMPLE)
      StartDrawing(ImageOutput(#IMG_TEXTEEXEMPLE))
      DrawingMode(#PB_2DDrawing_Transparent)
      Box(0,0,792*FacteurEchelleX,HauteurPoliceSysteme+8,#COUL_FONDTEXTETITRE)
      DrawText(10,4,ArgNomPolice+" "+ArgTexteComplement,#COUL_TEXTETITRE)
      DrawingFont(FontID(#POLICE))
      DrawText(8,HauteurPoliceSysteme+12,#TEXTETEST,#COUL_TEXTEEXEMPLE)
      StopDrawing()
      OpenGadgetList(#GAD_FP_ZD_GALERIE)
      ImageGadget(NoGadget,4,ArgPositionY/FacteurEchelleY,792,HauteurImage,ImageID(#IMG_TEXTEEXEMPLE))
      GadgetToolTip(NoGadget,Str(ArgCompteur)+" • "+ArgFichier)
      SetGadgetData(NoGadget,ArgCompteur)
      CloseGadgetList()
      ;SaveImage(#IMG_TEXTEEXEMPLE,"C:\Temp\Temp"+Str(ArgCompteur)+".png",#PB_ImagePlugin_PNG)
      FreeImage(#IMG_TEXTEEXEMPLE)
    EndIf
    FreeFont(#POLICE)
    ProcedureReturn HauteurImage
  EndIf
EndProcedure


If OpenWindow(#CGP_FENPRINCIPALE, 0, 0, 800, 200, "Exemple...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ScrollAreaGadget(#GAD_FP_ZD_GALERIE,4,4,792,192,792,192)
  ; 
  StartDrawing(WindowOutput(#CGP_FENPRINCIPALE))
  HauteurPoliceSysteme=TextHeight("Ly")
  StopDrawing()
  For Compteur.a=0 To 5
    Select Compteur
      Case 0:NomPolice.s="Arial":FichierPolice.s="C:\WINDOWS\Fonts\ARIAL.TTF":Style.u=64
      Case 1:NomPolice.s="Arial":FichierPolice.s="C:\WINDOWS\Fonts\ARIALBD.TTF":Style=32
      Case 2:NomPolice.s="Arial":FichierPolice.s="C:\WINDOWS\Fonts\ARIALBI.TTF":Style=33
      Case 3:NomPolice.s="Arial":FichierPolice.s="C:\WINDOWS\Fonts\ARIALI.TTF":Style=1
      Case 4:NomPolice.s="Arial Black":FichierPolice.s="C:\WINDOWS\Fonts\ARIBLK.TTF":Style=64
      Case 5:NomPolice.s="Arial Narrow":FichierPolice.s="C:\WINDOWS\Fonts\ARIALNBI.TTF":Style=33
    EndSelect
    HauteurImage=Fc_Affichage_ImagePolice(FichierPolice,NomPolice,Style,"",CompteurGadget,PositionY)
    If HauteurImage
      PositionY+HauteurImage
      CompteurGadget+1
    EndIf
  Next
  SetGadgetAttribute(#GAD_FP_ZD_GALERIE,#PB_ScrollArea_InnerHeight,PositionY/FacteurEchelleY)
  
  Repeat
    Event = WaitWindowEvent()
    Select Event
      Case #PB_Event_Gadget
        Select EventGadget()
        EndSelect
    EndSelect
  Until Event = #PB_Event_CloseWindow
EndIf

Procedure.u Fc_Affichage_ImagePolice2(ArgFichier.s,ArgNomPolice.s,ArgStyle.u,ArgTexteComplement.s,ArgCompteur.u,ArgPositionY.l)
  Debug #PB_Compiler_Procedure+" (Fichier="+ArgFichier+",NomPolice="+ArgNomPolice+",TexteComplement="+ArgTexteComplement+",Compteur="+ArgCompteur+",PositionY="+ArgPositionY+")",5
  Protected.u PositionY,HauteurImage,LargeurTexte,HauteurTexte,Style
  
  If RegisterFontFile(ArgFichier)
    If ArgStyle&1:Style=#PB_Font_Italic:EndIf        ; Italique
    If ArgStyle>>1&1:Style|#PB_Font_Underline:EndIf  ; Souligné
    If ArgStyle>>4&1:Style|#PB_Font_StrikeOut:EndIf  ; Barré
    If ArgStyle>>5&1:Style|#PB_Font_Bold:EndIf       ; Gras
    LoadFont(#POLICE,ArgNomPolice,24,Style)
    StartDrawing(WindowOutput(0))
    DrawingFont(FontID(#POLICE))
    LargeurTexte=TextWidth(#TEXTETEST):HauteurTexte=TextHeight(#TEXTETEST)
    StopDrawing()
    PositionY=HauteurTexte+8:HauteurImage=HauteurPoliceSysteme+8+PositionY
    If CreateImage(#IMG_TEXTEEXEMPLE,792*FacteurEchelleX,HauteurImage,32,#COUL_FONDTEXTEEXEMPLE)
      StartDrawing(ImageOutput(#IMG_TEXTEEXEMPLE))
      DrawingMode(#PB_2DDrawing_Transparent)
      Box(0,0,792*FacteurEchelleX,HauteurPoliceSysteme+8,#COUL_FONDTEXTETITRE)
      DrawText(10,4,ArgNomPolice+" "+ArgTexteComplement,#COUL_TEXTETITRE)
      DrawingFont(FontID(#POLICE))
      DrawText(8,HauteurPoliceSysteme+12,#TEXTETEST,#COUL_TEXTEEXEMPLE)
      StopDrawing()
      UsePNGImageEncoder()
      ImageGadget(#GAD_FP_IMG_0+ArgCompteur,4,ArgPositionY/FacteurEchelleY,792,HauteurImage,ImageID(#IMG_TEXTEEXEMPLE))
      GadgetToolTip(#GAD_FP_IMG_0+ArgCompteur,ArgFichier)
    EndIf
    FreeFont(#POLICE)
    FreeImage(#IMG_TEXTEEXEMPLE)
    ProcedureReturn HauteurImage
  EndIf
EndProcedure

The problem in my complete code is that, while the images are created correctly, the ImageGadgets don't appear, even though an ID is returned with a Debug (not 0).
I've tried all kinds of manipulations, with no results.

I'm beginning to wonder whether this might be due to the fact that the gadget creation procedure is launched inside the thread (as many calls as there are gadgets to create).
Is this the case? If so, how can gadgets be created from within a thread?
If my English syntax and lexicon are incorrect, please bear with Google translate and DeepL. They rarely agree with each other!
Except on this sentence...
infratec
Always Here
Always Here
Posts: 7664
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Thread and gadget creation

Post by infratec »

Never do GUI stuff in a thread.

Use PostEvent() and do this in the main thread.
User avatar
jacdelad
Addict
Addict
Posts: 2032
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: Thread and gadget creation

Post by jacdelad »

https://www.purebasic.fr/english/viewtopic.php?t=66180
This doesn't include creation, but handling. If said gadgets aren't dynamic, you can create them beforehand and hide/unhide them from the thread.
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
boddhi
Enthusiast
Enthusiast
Posts: 524
Joined: Mon Nov 15, 2010 9:53 pm

Re: Thread and gadget creation

Post by boddhi »

Thank you Infratec for your reply.
infratec wrote: Never do GUI stuff in a thread. Use PostEvent() and do this in the main thread.
Ok, I notice (which reminded me of certain discussions on the subject that I hadn't fully considered). :wink:

One question though, does PostEvent() block thread execution? Because each gadget created requires the previous gadget to have been completely created to be positioned correctly, and therefore the thread execution must be blocked for the time of creation. Or PauseThred() is needed ?

jacdelad wrote: This doesn't include creation, but handling. If said gadgets aren't dynamic, you can create them beforehand and hide/unhide them from the thread.
I know that for sure ! :) :D
I use and abuse it to hide/unhide containers, progress bars, etc.
If my English syntax and lexicon are incorrect, please bear with Google translate and DeepL. They rarely agree with each other!
Except on this sentence...
User avatar
jacdelad
Addict
Addict
Posts: 2032
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: Thread and gadget creation

Post by jacdelad »

Use own events to communicate when a gadget is ready.
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
boddhi
Enthusiast
Enthusiast
Posts: 524
Joined: Mon Nov 15, 2010 9:53 pm

Re: Thread and gadget creation

Post by boddhi »

jacdelad wrote: Fri Jan 19, 2024 9:54 am Use own events to communicate when a gadget is ready.
But it doesn't reply to my question : PostEvent() block thread execution until it has finished? or PauseThred() is needed?
If my English syntax and lexicon are incorrect, please bear with Google translate and DeepL. They rarely agree with each other!
Except on this sentence...
Fred
Administrator
Administrator
Posts: 18351
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Thread and gadget creation

Post by Fred »

PostEvent() doesn't block.
boddhi
Enthusiast
Enthusiast
Posts: 524
Joined: Mon Nov 15, 2010 9:53 pm

Re: Thread and gadget creation

Post by boddhi »

Fred wrote: Fri Jan 19, 2024 10:10 am PostEvent() doesn't block.
Thanks Fred for your reply.
I've just done some tests and I can confirm :( :D
If my English syntax and lexicon are incorrect, please bear with Google translate and DeepL. They rarely agree with each other!
Except on this sentence...
boddhi
Enthusiast
Enthusiast
Posts: 524
Joined: Mon Nov 15, 2010 9:53 pm

Re: Thread and gadget creation

Post by boddhi »

I've found a solution :

Code: Select all

; Main procedure (Thread)
Debug "PositionY before : "+DonneesGadget\PositionY
PostEvent(#EVNMT_CREATIONGADGETIMAGE,#CGP_FENPRINCIPALE,0,0,@DonneesGadget)
Delay(50) ; => My solution
Debug "PositionY after : "+DonneesGadget\PositionY ; To control if my variable has been correctly modified by the procedure executed through PostEvent()
ImageHeight=DonneesGadget\PositionY
If ImageHeight
  PositionY+ImageHeight
  GadgetCount+1
EndIf
But (because there is always a but):
1) Is Delay() THE RIGHT solution to give the procedure time to be called and executed?
2) If yes, how can I be sure that this delay, which is sufficient for my PC, will be sufficient for another?
Last edited by boddhi on Fri Jan 19, 2024 1:39 pm, edited 1 time in total.
If my English syntax and lexicon are incorrect, please bear with Google translate and DeepL. They rarely agree with each other!
Except on this sentence...
User avatar
jacdelad
Addict
Addict
Posts: 2032
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: Thread and gadget creation

Post by jacdelad »

That's what I meant with my last post: let the thread fire a custom event which tells the main program, that it can continue (when handling the event, set a variable or something).
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
boddhi
Enthusiast
Enthusiast
Posts: 524
Joined: Mon Nov 15, 2010 9:53 pm

Re: Thread and gadget creation

Post by boddhi »

jacdelad wrote: Fri Jan 19, 2024 1:34 pm That's what I meant with my last post: let the thread fire a custom event which tells the main program, that it can continue (when handling the event, set a variable or something).
You know, I understand very quickly, but you have to explain it to me for a long long time. :mrgreen: :wink:

So, if I've understood what you're saying, it would be to create, after PostEvent(), a loop that would check the content of a variable and until the content of this variable is not confirmed, continue to loop? that's right? and Delay(X) needed or not needed in this case ?
If my English syntax and lexicon are incorrect, please bear with Google translate and DeepL. They rarely agree with each other!
Except on this sentence...
User avatar
jacdelad
Addict
Addict
Posts: 2032
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: Thread and gadget creation

Post by jacdelad »

Nah...
...while running your thread your program remains in the main loop (and you know, you should only run one). The thread sends a message via Post message, which is processed normally (Event(), EventType()...). Now, after sending the message, the threads waits and regularly checks a variable for a change. The main thread sets the variable after doing everything that has to be done. The variable changes, the thread is happy.
Something like this...
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
User avatar
mk-soft
Always Here
Always Here
Posts: 6321
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Thread and gadget creation

Post by mk-soft »

You can use 'SendEvent' from my Module ThreadToGUI
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
infratec
Always Here
Always Here
Posts: 7664
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Thread and gadget creation

Post by infratec »

Instead of a Delay() use WaitSemaphore() and SignalSemaphore()
boddhi
Enthusiast
Enthusiast
Posts: 524
Joined: Mon Nov 15, 2010 9:53 pm

Re: Thread and gadget creation

Post by boddhi »

jacdelad wrote: Fri Jan 19, 2024 5:46 pm ...while running your thread [...] Something like this...
Sincerly ? I didn't understood everything :oops: :mrgreen:
A very little example? :mrgreen:
mk-soft wrote: You can use 'SendEvent' from my Module ThreadToGUI
Thank you for your suggestion :wink:
infratec wrote: Instead of a Delay() use WaitSemaphore() and SignalSemaphore()
@mk-soft & infratec
It's already foggy in my skull. Add to that the semaphores, which I don't understand aanything about...hummmm 😭😭😭 :oops: :mrgreen:

For the moment, I do it like this 🤔 (Edit : I wrote "I'll do it" : Sorry, translation error :oops: )

Code: Select all

Procedure CalledProcedure(*buffer.structureX)
  [...]
  *buffer\JobDone=#True
EndProcedure

Procedure TreadedProcedure()
  Protected.structureX Variable
  [...]
  For
    [...]
    Variable\xxx=xxx
    Variable\yyy=yyy
    Variable\JobDone=#False
    PostEvent(#EVNMT,#WINDOW,0,0,@Variable)
    Delay(5)
    While Not Variable\JobDone:Wend
EndProcedure

Do
  Select WaitWindowEvent()
    [...]
    Case #EVNMT:CalledProcedure(EventData())
    [...]
  EndSelect
Forever
If my English syntax and lexicon are incorrect, please bear with Google translate and DeepL. They rarely agree with each other!
Except on this sentence...
Post Reply