Long loop control window how to ?

Just starting out? Need help? Post your questions and find answers here.
wawavoun
User
User
Posts: 34
Joined: Fri Oct 18, 2019 4:49 pm

Long loop control window how to ?

Post by wawavoun »

Hello there !

I gradually discovered PureBasic by writing a program to drive an eprom programmer via rs232 and am satisfied with what I am learning little by little.

I understand event loops and I even manage to manage several windows but not yet with a task running in the background!

The skeleton of my code works but I stumble on this point.

An operation on the eprom can be quite long so a progress bar would be nice and also I wish I could possibly interrupt it.

So I imagine that launching the task in the main window opens a small control window with this progress bar and a start button and another stop button.

This window should be common to several different operations on the eprom so the code (basically a long loop) that performs this operation is in a subroutine (a different subroutine per operation).

How can I monitor the start and stop buttons of the control window in the loop and also that the progress bar being updated?

I tried different thing but without success so far ...

While browsing the doc I have the feeling that the piloting window should be a different thread from that of the main program ???

Here is a sample what I try to do :

Code: Select all

;
;
Global PilotWin
Global MainWin

Global ProgressBar_0, ButStart, ButStop
Global ButCalc


Procedure OpenPilotWin(x = 0, y = 0, width = 600, height = 400)
  PilotWin = OpenWindow(#PB_Any, x, y, width, height, "", #PB_Window_SystemMenu)
  ProgressBar_0 = ProgressBarGadget(#PB_Any, 180, 130, 270, 60, 0, 100)
  ButStart = ButtonGadget(#PB_Any, 170, 250, 100, 40, "Start")
  ButStop = ButtonGadget(#PB_Any, 360, 250, 90, 40, "Stop")
EndProcedure
;
;
Procedure OpenMainWin(x = 0, y = 0, width = 600, height = 400)
  MainWin = OpenWindow(#PB_Any, x, y, width, height, "", #PB_Window_SystemMenu)
  ButCalc = ButtonGadget(#PB_Any, 180, 210, 220, 40, "Calcul")
EndProcedure
;
;
Procedure.s Calculate()
  ;
  Define.i i, FlgButStart, FlgButStop
  ;
  OpenPilotWin()
  ;
  FlgBuSTop = #False
  FlgButStart = #False
  ;
  While FlgButStop = #False And FlgButStart = #False
  	; Here we wait ButStart or ButStop
  	; si ButStop --> FlgButStop = #True
  	; si ButStart --> FlgButStart = #True
  Wend
  ;
  If FlgButStop : CloseWindow(PilotWin) : ProcedureReturn "Aborted" : EndIf
  ;
  ; so it's ButCalc
  ;  
  For i=1 To 10000000
   	 ;
    	;
   	 SetGadgetState(ProgressBar_0, 100 * i / 10000000)
    	;
   	 ; Here look at ButStop
   	 ; If ButStop --> FlgButStop = #True
   	 ; and update ProgressBar_0
   	 ;
    	If FlgButStop : CloseWindow(PilotWin) : ProcedureReturn "Aborted" : EndIf
    	;
   	 ;
  Next i
  ;
  ;
  CloseWindow(PilotWin)
  ProcedureReturn "Finished"
  ;
  ;
EndProcedure

;
OpenMainWin()
;
;
Repeat
;  
  Event = WaitWindowEvent()
  ;
  Select Event
      ;
    Case #PB_Event_Menu
      ;
      Select EventMenu()
         ;
      EndSelect
      ;
    Case #PB_Event_Gadget
      ;
      Select EventGadget()
        ;
        Case ButCalc : Debug Calculate()
          ;
      EndSelect
      ;
  EndSelect
  ;
Until Event = #PB_Event_CloseWindow
;
Hope this is clear enough ...

Maybe you have this in your drawers?

Thank you. Best regards.
Philippe
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Long loop control window how to ?

Post by infratec »

For such a thing and ... for serial communication you need threads.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Long loop control window how to ?

Post by infratec »

Quick hack:

Code: Select all

CompilerIf Not #PB_Compiler_Thread
  CompilerError "Enable Threadsafe!"
CompilerEndIf


EnableExplicit


Enumeration #PB_Event_FirstCustomValue
  #CalculateProgress
  #CalculateFinished
EndEnumeration


Structure ThreadParameterStructure
  Thread.i
  Semaphore.i
  FinishReason$
  Exit.i
EndStructure

;
Global PilotWin
Global MainWin

Global ProgressBar_0, ButStart, ButStop
Global ButCalc


Procedure OpenPilotWin(x = 0, y = 0, width = 600, height = 400)
  PilotWin = OpenWindow(#PB_Any, x, y, width, height, "", #PB_Window_SystemMenu)
  ProgressBar_0 = ProgressBarGadget(#PB_Any, 180, 130, 270, 60, 0, 100)
  ButStart = ButtonGadget(#PB_Any, 170, 250, 100, 40, "Start")
  ButStop = ButtonGadget(#PB_Any, 360, 250, 90, 40, "Stop")
  DisableGadget(ButStop, #True)
EndProcedure
;
;
Procedure OpenMainWin(x = 0, y = 0, width = 600, height = 400)
  MainWin = OpenWindow(#PB_Any, x, y, width, height, "", #PB_Window_SystemMenu)
  ButCalc = ButtonGadget(#PB_Any, 180, 210, 220, 40, "Calcul")
EndProcedure
;
;
Procedure Calculate(*Parameter.ThreadParameterStructure)
  ;
  Protected.i i
  ;
  
  For i=1 To 100
    ;
    Debug i
    ;
    PostEvent(#CalculateProgress, PilotWin, ProgressBar_0, 0, i)
    If *Parameter\Exit
      *Parameter\FinishReason$ = "canceled"
      Break
    EndIf
    
    Delay(100)
    
  Next i
  ;
  ;
  If *Parameter\FinishReason$ = ""
    *Parameter\FinishReason$ = "finished"
  EndIf
  
  PostEvent(#CalculateFinished, PilotWin, 0)
  ;
  ;
EndProcedure

;

Define.i Exit, Event
Define ThreadParameter.ThreadParameterStructure


ThreadParameter\Semaphore = CreateSemaphore()

OpenMainWin()
;
;
Repeat
  ;  
  Event = WaitWindowEvent()
  ;
  
  Select EventWindow()
    Case MainWin
      
      Select Event
          ;
        
          
        Case #PB_Event_CloseWindow
          Exit = #True
          
        Case #PB_Event_Menu
          ;
          Select EventMenu()
              ;
          EndSelect
          ;
        Case #PB_Event_Gadget
          ;
          Select EventGadget()
              ;
            Case ButCalc
              DisableGadget(ButCalc, #True)
              OpenPilotWin()
              
              ;
          EndSelect
          ;
      EndSelect
      ;
    Case PilotWin
      Select Event
        Case #CalculateFinished
          CloseWindow(PilotWin)
          DisableGadget(ButCalc, #False)
          SetActiveWindow(MainWin)
          
        Case #CalculateProgress
          SetGadgetState(EventGadget(), EventData())
          
        Case #PB_Event_CloseWindow
          If IsThread(ThreadParameter\Thread)
            ThreadParameter\Exit = #True
          Else
            PostEvent(#CalculateFinished, PilotWin, 0)
          EndIf
          
        Case #PB_Event_Gadget
          Select EventGadget()
            Case ButStart
              DisableGadget(ButStart, #True)
              DisableGadget(ButStop, #False)
              ThreadParameter\Exit = #False
              ThreadParameter\Thread = CreateThread(@Calculate(), @ThreadParameter)
              
            Case ButStop
              DisableGadget(ButStart, #False)
              DisableGadget(ButStop, #True)
              ThreadParameter\Exit = #True
          EndSelect
          
          
      EndSelect
      
  EndSelect
  
Until Exit


If IsThread(ThreadParameter\Thread)
  ThreadParameter\Exit = #True
  If WaitThread(ThreadParameter\Thread, 1000) = 0
    KillThread(ThreadParameter\Thread)
  EndIf
EndIf


FreeSemaphore(ThreadParameter\Semaphore)
I don't think you understood already the multi window stuff :wink:

And also for your serial stuff you will need sooner or later a thread, else you will run into trouble.
Or this thread is already the serial thread, then you don't need an other.

In general:

use EnableExplicit
No GUI actions inside threads. Maybe it works in windows, but I don't think you can rely on this.
If you want to show strings with PostEvent, you need the semaphore, else the string maybe overwritten until he is shown.
And don't send to many PostEvent() maybe you should use an if with a modulo operator to show only every 100 bytes or whatever.
wawavoun
User
User
Posts: 34
Joined: Fri Oct 18, 2019 4:49 pm

Re: Long loop control window how to ?

Post by wawavoun »

Hello,

Thanks for the modified code and all the tips !

I know I have a lot to learn !

Regards.
Philippe
wawavoun
User
User
Posts: 34
Joined: Fri Oct 18, 2019 4:49 pm

Re: Long loop control window how to ?

Post by wawavoun »

Hello,

Thanks to infratec I have a working set up for my question about what I call a "pilot" window.

I use threads, the progress bar is working and I can start an stop the thread with the two buttons... Perfect !

Now the next question :

One thread will read eprom data and another one will write data to eprom. Both are never working at same time of course...

All the eprom bytes are basically read (then send to serial port) or write (coming from the serial port) from or to a global unsigned byte (.a) array.

I have understand that only one parameter could be passed to a thread so infratec use a structure as this parameter with various fields accordingly to what to do.
I have already add the serial port file number to use, the eprom size etc... to this structure so the threaded procedure can work properly.

Is it possible to add a pointer to this array to this structure ? Then I assume I have to use mutex at various place into the code to be sure that the array is only accessed by only one thread at a time ?

Again the code herunder show what I try to do...
<XXX> instructions are unsure for me... Now I learn pointer !

Code: Select all

CompilerIf Not #PB_Compiler_Thread
  CompilerError "Enable Threadsafe!"
CompilerEndIf

EnableExplicit


Enumeration #PB_Event_FirstCustomValue
  #CalculateProgress
  #CalculateFinished
EndEnumeration

Global Dim CountArray.i(2048)

Structure ThreadParameterStructure
  Thread.i
  Semaphore.i
  FinishReason$
  Exit.i
 <POINTER_TO_ARRAY CountArray()>
EndStructure

;
Global PilotWin
Global MainWin

Global ProgressBar_0, ButStart, ButStop
Global ButCalc

Mutex = CreateMutex()

Procedure OpenPilotWin(x = 0, y = 0, width = 600, height = 400)
  PilotWin = OpenWindow(#PB_Any, x, y, width, height, "", #PB_Window_SystemMenu)
  ProgressBar_0 = ProgressBarGadget(#PB_Any, 180, 130, 270, 60, 0, 100)
  ButStart = ButtonGadget(#PB_Any, 170, 250, 100, 40, "Start")
  ButStop = ButtonGadget(#PB_Any, 360, 250, 90, 40, "Stop")
  DisableGadget(ButStop, #True)
EndProcedure
;
;
Procedure OpenMainWin(x = 0, y = 0, width = 600, height = 400)
  MainWin = OpenWindow(#PB_Any, x, y, width, height, "", #PB_Window_SystemMenu)
  ButCalc = ButtonGadget(#PB_Any, 180, 210, 220, 40, "Calcul")
EndProcedure
;
;
Procedure Calculate(*Parameter.ThreadParameterStructure)
  ;
  Protected.i count
  Shared Mutex
  
  ;
  LockMutex(Mutex)
  ;
  <  *POINTER = *Parameter\<POINTER_TO_ARRAY> >
  ;
  For count=1 To 100
    ;
    Debug i
    ;
    PostEvent(#CalculateProgress, PilotWin, ProgressBar_0, 0, i)
    If *Parameter\Exit
      *Parameter\FinishReason$ = "canceled"
      Break
    EndIf
    
    Delay(100)
    
    < *POINTER\i = count >
    
    < *POINTER = *POINTER + SIZEOF(INTEGER) >
    
  Next count
  ;
  ;
  If *Parameter\FinishReason$ = ""
    *Parameter\FinishReason$ = "finished"
  EndIf
  
  PostEvent(#CalculateFinished, PilotWin, 0)
  ;
  UnLockMutex(Mutex)
  ;
EndProcedure

;

Define.i Exit, Event
Define ThreadParameter.ThreadParameterStructure


ThreadParameter\Semaphore = CreateSemaphore()

OpenMainWin()
;
;
Repeat
  ;  
  Event = WaitWindowEvent()
  ;
  
  Select EventWindow()
    Case MainWin
      
      Select Event
          ;
        
          
        Case #PB_Event_CloseWindow
          Exit = #True
          
        Case #PB_Event_Menu
          ;
          Select EventMenu()
              ;
          EndSelect
          ;
        Case #PB_Event_Gadget
          ;
          Select EventGadget()
              ;
            Case ButCalc
              DisableGadget(ButCalc, #True)
              OpenPilotWin()
              
              ;
          EndSelect
          ;
      EndSelect
      ;
    Case PilotWin
      Select Event
        Case #CalculateFinished
          CloseWindow(PilotWin)
          DisableGadget(ButCalc, #False)
          SetActiveWindow(MainWin)
          
        Case #CalculateProgress
          SetGadgetState(EventGadget(), EventData())
          
        Case #PB_Event_CloseWindow
          If IsThread(ThreadParameter\Thread)
            ThreadParameter\Exit = #True
          Else
            PostEvent(#CalculateFinished, PilotWin, 0)
          EndIf
          
        Case #PB_Event_Gadget
          Select EventGadget()
            Case ButStart
              DisableGadget(ButStart, #True)
              DisableGadget(ButStop, #False)
              ThreadParameter\Exit = #False
              ThreadParameter\Thread = CreateThread(@Calculate(), @ThreadParameter)
              
            Case ButStop
              DisableGadget(ButStart, #False)
              DisableGadget(ButStop, #True)
              ThreadParameter\Exit = #True
          EndSelect
          
          
      EndSelect
      
  EndSelect
  
Until Exit


If IsThread(ThreadParameter\Thread)
  ThreadParameter\Exit = #True
  If WaitThread(ThreadParameter\Thread, 1000) = 0
    KillThread(ThreadParameter\Thread)
  EndIf
EndIf


FreeSemaphore(ThreadParameter\Semaphore)
Thanks for the help.

Philippe
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Long loop control window how to ?

Post by mk-soft »

Just a quick example to point in the right direction.
Learning to use structures and pointers is important.

Update

Code: Select all

Global Dim CountArray.a(2048) ; Array of Unsigned Byte 0..2048

For i = 0 To 10
  CountArray(i) = i
Next

Structure ArrayOfUByte
  a.a[0] ; Size [0] -> Array if unsigned byte with unknown size
EndStructure

Structure ThreadParameterStructure
  Thread.i
  Semaphore.i
  FinishReason$
  Exit.i
  ; Way one
  Array CountArray.a(0)
  ; Way Two
  *pCountArray.ArrayOfUByte
EndStructure

Define ThreadParameter.ThreadParameterStructure

; Way one by copy
CopyArray(CountArray(), ThreadParameter\CountArray())
Debug ArraySize(ThreadParameter\CountArray()) + 1

; Way two bei pointer
ThreadParameter\pCountArray = @CountArray()
For i = 0 To 11
  Debug ThreadParameter\pCountArray\a[i]
Next

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
Post Reply