Page 1 of 1
GUI responsiveness or Event handling
Posted: Fri Jun 14, 2024 4:32 pm
by Erolcum
I write an article for beginners like me in my blog. Codes show two solutions to make gui responsive when program enters a long delayed procedure. May an experienced programmer show another solution by using a thread ? if possible
I simplified the codes from @Axolotl
my article
https://erolcum-blogspot-com.translate ... r_pto=wapp
// Moved from "Tricks und Tipps" to "Coding Questions" (Kiffi)
Re: GUI responsiveness or Event handling
Posted: Fri Jun 14, 2024 6:38 pm
by infratec
I personally always got a horror when I see a procedure inside of the normal code flow.
And ... it is very bad to use more then one event loop.
You can always loose events for the other loop.
In windows it is more or less possible to access the GUI stuff from a thread (SetGadgetText())
but in the other OSs this will fail definately.
You should always do such things in the main event loop via PostEvent().
And you did not use EnableExplicit. This can result in long debugging sessions.
Maybe when I later have a bit more time, I will modify the code how I would do it.
Re: GUI responsiveness or Event handling
Posted: Fri Jun 14, 2024 7:14 pm
by Erolcum
Yes you are absolutely right about nested procedures. I would really like to see your solution when it becomes available. Thanks @infratec
Re: GUI responsiveness or Event handling
Posted: Fri Jun 14, 2024 7:25 pm
by infratec
Code: Select all
Case #PB_Event_CloseWindow
ApplicationQuit = #True
End
The End makes no sense
And it makes 'cleaning up' impossible.
Re: GUI responsiveness or Event handling
Posted: Fri Jun 14, 2024 8:02 pm
by infratec
I hope everything what you want is included:
Code: Select all
EnableExplicit
CompilerIf Not #PB_Compiler_Thread
CompilerError "Enable thread safe in compiler options!"
CompilerEndIf
#WINDOW_Main = 0
#WINDOW_Main_Flags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
#LOOP_MaxLoops = 200
#LOOP_SlowDownDelay = 100
Enumeration Gadget
#GADGET_btnStart
#GADGET_btnStop
#GADGET_chkTest
#GADGET_txtLoopOutput
#GADGET_lbTrace
EndEnumeration
Enumeration OwnEvent #PB_Event_FirstCustomValue
#OwnEvent_ThreadStarted
#OwnEvent_SetGadgetText
#OwnEvent_ThreadFinished
EndEnumeration
Structure Parameter_Structure
Thread.i
Exit.i
EndStructure
Macro Trace(MessageText)
AddGadgetItem(#GADGET_lbTrace, -1, MessageText)
SetGadgetState(#GADGET_lbTrace, CountGadgetItems(#GADGET_lbTrace) -1)
EndMacro
Procedure Test_LongLoop(*Parameter.Parameter_Structure)
Protected index.i, *msg
PostEvent(#OwnEvent_ThreadStarted)
For index = 0 To #LOOP_MaxLoops
If *Parameter\Exit
Break
EndIf
Delay(#LOOP_SlowDownDelay) ; spend some time with nothing
*msg = UTF8(" Item " + Str(index) + "/" + Str(#LOOP_MaxLoops) + " | Checkbox.State == " + GetGadgetState(#GADGET_chkTest))
PostEvent(#OwnEvent_SetGadgetText, #WINDOW_Main, #GADGET_txtLoopOutput, 0, *msg)
Next index
*msg = UTF8("Loop finished (reached MaxLoops == " + Str(index) + ")")
PostEvent(#OwnEvent_ThreadFinished, #WINDOW_Main, #GADGET_lbTrace, 0, *msg)
EndProcedure
Define.i Event, ApplicationQuit, Exit
Define *msg
Define Parameter.Parameter_Structure
OpenWindow(#WINDOW_Main, 0, 0, 400, 320, "Event handling example...", #WINDOW_Main_Flags)
StickyWindow(#WINDOW_Main, 1) ; show test app always above the PB_IDE
ButtonGadget(#GADGET_btnStart, 8, 4, 192, 32, "Start Looping")
ButtonGadget(#GADGET_btnStop, 200, 4, 192, 32, "Stop Looping")
DisableGadget(#GADGET_btnStop, #True)
CheckBoxGadget(#GADGET_chkTest, 8, 40, 384, 24, "Check me -- (see the event handling while the loop is running)")
TextGadget(#GADGET_txtLoopOutput, 8, 72, 384, 20, "Loop is stopped.")
SetGadgetColor(#GADGET_txtLoopOutput, #PB_Gadget_BackColor, GetSysColor_(#COLOR_INFOBK))
ListViewGadget(#GADGET_lbTrace, 8, 104, 384, 208, $4000) ; #LBS_NOSEL == 0x4000
Repeat
Event = WaitWindowEvent()
Select Event
Case #OwnEvent_ThreadStarted
DisableGadget(#GADGET_btnStart, #True)
DisableGadget(#GADGET_btnStop, #False)
SetGadgetText(#GADGET_txtLoopOutput, "Loop is running")
Case #OwnEvent_SetGadgetText
*msg = EventData()
SetGadgetText(EventGadget(), PeekS(*msg, -1, #PB_UTF8))
FreeMemory(*msg)
Case #OwnEvent_ThreadFinished
DisableGadget(#GADGET_btnStart, #False)
DisableGadget(#GADGET_btnStop, #True)
*msg = EventData()
If *msg
Trace(PeekS(*msg, -1, #PB_UTF8))
FreeMemory(*msg)
EndIf
SetGadgetText(#GADGET_txtLoopOutput, "Loop stopped.")
If ApplicationQuit
Exit = #True
EndIf
Case #PB_Event_MoveWindow
Trace(" New Window Pos == " + WindowX(#WINDOW_Main) + ", " +WindowY(#WINDOW_Main))
Case #PB_Event_CloseWindow
ApplicationQuit = #True
If IsThread(Parameter\Thread)
Parameter\Exit = #True
Else
PostEvent(#OwnEvent_ThreadFinished)
EndIf
Case #PB_Event_Gadget
Select EventGadget()
Case #GADGET_btnStart
ClearGadgetItems(#GADGET_lbTrace)
Parameter\Exit = #False
Parameter\Thread = CreateThread(@Test_LongLoop(), @Parameter)
Case #GADGET_btnStop
If IsThread(Parameter\Thread)
Parameter\Exit = #True
EndIf
Case #GADGET_chkTest
Trace("Gadget = #GADGET_chkTest == " + GetGadgetState(#GADGET_chkTest))
EndSelect
EndSelect
Until Exit
This code should work an all OSs.
Re: GUI responsiveness or Event handling
Posted: Fri Jun 14, 2024 8:45 pm
by Erolcum
Thank you very much for your quick and excellent answer. You really make purebasic sing a song that you want
It will take some time to digest the codes you wrote.
Re: GUI responsiveness or Event handling
Posted: Fri Jun 14, 2024 9:26 pm
by infratec
Ups ...
Is not cross platform.
And ... you can not compile it with the PB demo version.
For a beginner tutorial you should only use examples which can be compiled with the demo version.
Re: GUI responsiveness or Event handling
Posted: Fri Jun 14, 2024 9:56 pm
by Erolcum
ok. I will place it correctly in my blog. Code comes from another forum user

Re: GUI responsiveness or Event handling
Posted: Mon Jul 01, 2024 1:09 pm
by Erolcum
OK. I corrected the issues in my blog. Thank you again @infratec.