Page 1 of 1
How to refresh?
Posted: Wed Jun 16, 2021 7:13 pm
by platy
Hi all,
I log messages to a listview gadget via AddItem(). When a time-consuming command immediately follows my log command (such as deleting a large dir tree via DeleteDirectory), the message(s) show up in the listview AFTER the time-consuming command finishes.
How do I get them to show up immediately BEFORE the time-consuming command runs?
Thanks for any suggestions!
Re: How to refresh?
Posted: Wed Jun 16, 2021 7:18 pm
by GPI
you must handle the windows-events
will do it, BUT it ignores all events!
Re: How to refresh?
Posted: Wed Jun 16, 2021 8:05 pm
by platy
Oops, forgot to mention that my code runs in a callback proc (after a button click) so I cannot call WaitEvent/WaitWindowEvent in there ...
Re: How to refresh?
Posted: Thu Jun 17, 2021 7:48 am
by infratec
For long running code you need a thread.
Re: How to refresh?
Posted: Thu Jun 17, 2021 8:19 am
by RASHAD
It will be very helpful if you posted a very simple exam.to show how you run your commands with windows callback
Re: How to refresh?
Posted: Thu Jun 17, 2021 5:33 pm
by platy
Like so:
Code: Select all
EnableExplicit
Enumeration Gadgets
#CurWindow
#ButtonStart
#ListviewLog
EndEnumeration
#DateTimeFormat = "%yyyy-%mm-%dd %hh:%ii:%ss" ; ISO 8601
Procedure LogMessage(Msg.s)
AddGadgetItem(#ListviewLog, -1, FormatDate(#DateTimeFormat, Date()) + " " + Msg)
EndProcedure
Procedure ButtonClick()
ClearGadgetItems(#ListviewLog)
LogMessage("Process started.")
; now start a time consuming process here (in my case, deleting a huge dir tree)
; the log message only shows up upon completion of that process
EndProcedure
Procedure OpenFormWindow()
If OpenWindow(#CurWindow, #PB_Ignore, #PB_Ignore, 800, 600, "Issue Demo", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
ButtonGadget(#ButtonStart, 10, 10, 80, 25, "Start")
ListViewGadget(#ListviewLog, 10, 40, 780, 550)
BindGadgetEvent(#ButtonStart, @ButtonClick())
EndIf
EndProcedure
OpenFormWindow()
Define Event
Repeat
Event = WaitWindowEvent()
Select Event
; ...
EndSelect
Until Event = #PB_Event_CloseWindow
Re: How to refresh?
Posted: Thu Jun 17, 2021 5:53 pm
by Marc56us
Example of a thread that updates the main interface (yes, you can, as long as the updated gadget is not accessed at the same time by another part of the program).
With this system, the interface is not blocked during the Deltree
Code: Select all
EnableExplicit
Enumeration Gadgets
#CurWindow
#ButtonStart
#ListviewLog
EndEnumeration
#DateTimeFormat = "%yyyy-%mm-%dd %hh:%ii:%ss" ; ISO 8601
Procedure LogMessage(Msg.s)
AddGadgetItem(#ListviewLog, -1, FormatDate(#DateTimeFormat, Date()) + " " + Msg)
EndProcedure
; --- main task running in thread
Procedure DeleteTree(*value)
Protected i
Repeat
i + 1
; --- Yes, you can update main GUI if no other task modify the gadget
LogMessage("Hi " + Str(i))
Delay(1000)
ForEver
EndProcedure
Procedure ButtonClick()
ClearGadgetItems(#ListviewLog)
LogMessage("Process started.")
; now start a time consuming process here (in my case, deleting a huge dir tree)
; the log message only shows up upon completion of that process
; Main task
CreateThread(@DeleteTree(), 1)
EndProcedure
Procedure OpenFormWindow()
If OpenWindow(#CurWindow, #PB_Ignore, #PB_Ignore, 800, 600, "Issue Demo", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
ButtonGadget(#ButtonStart, 10, 10, 80, 25, "Start")
ListViewGadget(#ListviewLog, 10, 40, 780, 550)
BindGadgetEvent(#ButtonStart, @ButtonClick())
EndIf
EndProcedure
OpenFormWindow()
Define Event
Repeat
Event = WaitWindowEvent()
Select Event
; ...
EndSelect
Until Event = #PB_Event_CloseWindow
But you can't show the state of DeleteDirectory() because it's au single command.
You can "pass the time" by making a fake progressbar (i.e update sec by sec)
Check [X] ThreadSafe in compiler option.

Re: How to refresh?
Posted: Thu Jun 17, 2021 6:14 pm
by GPI
IMPORTANT. You should not call Gadget/Windows-Commands in Threads. It works on Windows, but not on other os.
Re: How to refresh?
Posted: Thu Jun 17, 2021 8:46 pm
by Marc56us
GPI wrote: Thu Jun 17, 2021 6:14 pm
IMPORTANT. You should not call Gadget/Windows-Commands in Threads. It works on Windows, but not on other os.
Tested on Linux Slackware with PB 5.73 LTS x64: Work fine
I don't have a mac, but knowing that they are based on *BSD it must also work, I think.
Maybe it was valid for the old versions of PB?
So far I never had any problem, but all my programs are still very "basic": I almost never use pointers for example and very rarely direct API calls
Re: How to refresh?
Posted: Thu Jun 17, 2021 8:53 pm
by mk-soft
On Linux work perhaps, but not stable ...
Re: How to refresh?
Posted: Thu Jun 17, 2021 9:05 pm
by platy
@Marcus:
Hmm - not so sure about your solution. As it stands, it works flawlessly or so it seems. The moment I add a WaitThread(), it hangs.
However, if I remove the GUI calls it works with WaitThread().
Re: How to refresh?
Posted: Thu Jun 17, 2021 9:11 pm
by mk-soft
Solution with PostEvent ... Not the first
Update
- macOS don't like running thread ...
Code: Select all
EnableExplicit
Procedure AllocateString(Text.s)
Protected *mem.String
*mem = AllocateStructure(String)
If *mem
*mem\s = Text
EndIf
ProcedureReturn *mem
EndProcedure
Procedure.s FreeString(*Mem.String)
Protected r1.s
If *Mem
r1 = *Mem\s
FreeStructure(*Mem)
EndIf
ProcedureReturn r1
EndProcedure
; ----
Enumeration Gadgets
#CurWindow
#ButtonStart
#ListviewLog
EndEnumeration
#DateTimeFormat = "%yyyy-%mm-%dd %hh:%ii:%ss" ; ISO 8601
Enumeration CustomEvent #PB_Event_FirstCustomValue
#MyEvent_LogMessage
EndEnumeration
Procedure DispatchLogMessage()
AddGadgetItem(#ListviewLog, -1, FormatDate(#DateTimeFormat, Date()) + " " + FreeString(EventData()))
EndProcedure
BindEvent(#MyEvent_LogMessage, @DispatchLogMessage())
Procedure LogMessage(Msg.s)
PostEvent(#MyEvent_LogMessage, 0, 0, 0, AllocateString(Msg))
EndProcedure
Global ExitThreads
; --- main task running in thread
Procedure DeleteTree(*value)
Protected i
Repeat
i + 1
; --- Yes, you can update main GUI if no other task modify the gadget
LogMessage("Hi " + Str(i))
Delay(1000)
Until ExitThreads
EndProcedure
Procedure ButtonClick()
ClearGadgetItems(#ListviewLog)
LogMessage("Process started.")
; now start a time consuming process here (in my case, deleting a huge dir tree)
; the log message only shows up upon completion of that process
; Main task
CreateThread(@DeleteTree(), 1)
EndProcedure
Procedure OpenFormWindow()
If OpenWindow(#CurWindow, #PB_Ignore, #PB_Ignore, 800, 600, "Issue Demo", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
ButtonGadget(#ButtonStart, 10, 10, 80, 25, "Start")
ListViewGadget(#ListviewLog, 10, 40, 780, 550)
BindGadgetEvent(#ButtonStart, @ButtonClick())
EndIf
EndProcedure
OpenFormWindow()
Define Event
Repeat
Event = WaitWindowEvent()
Select Event
; ...
EndSelect
Until Event = #PB_Event_CloseWindow
ExitThreads = #True
Delay(2000)
Re: How to refresh?
Posted: Fri Jun 18, 2021 2:08 am
by RASHAD
Hi
Did not test it but I hope it will do the job
Code: Select all
EnableExplicit
Global start,startflag
Enumeration Gadgets
#CurWindow
#ButtonStart
#ListviewLog
EndEnumeration
#DateTimeFormat = "%yyyy-%mm-%dd %hh:%ii:%ss" ; ISO 8601
Procedure LogMessage(Msg.s)
AddGadgetItem(#ListviewLog, -1, FormatDate(#DateTimeFormat, Date()) + " " + Msg)
EndProcedure
Procedure ButtonClick()
ClearGadgetItems(#ListviewLog)
LogMessage("Process started.")
startflag = 1
start = ElapsedMilliseconds()
; now start a time consuming process here (in my case, deleting a huge dir tree)
; the log message only shows up upon completion of that process
startflag = 0
EndProcedure
Procedure OpenFormWindow()
If OpenWindow(#CurWindow, #PB_Ignore, #PB_Ignore, 800, 600, "Issue Demo", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
ButtonGadget(#ButtonStart, 10, 10, 80, 25, "Start")
ListViewGadget(#ListviewLog, 10, 40, 780, 550)
BindGadgetEvent(#ButtonStart, @ButtonClick())
AddWindowTimer(#CurWindow,125,10)
EndIf
EndProcedure
OpenFormWindow()
Define Event
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Quit =1
Case #PB_Event_Timer
If startflag = 1
LogMessage(Str(ElapsedMilliseconds()-start) +" % Completed")
EndIf
; ...
EndSelect
Until Quit = 1
Re: How to refresh?
Posted: Fri Jun 18, 2021 9:29 am
by Marc56us
As indicated in the help, WaitThread() completely STOPS the main part of the program (partly like Delay, which STOPS ALL the program). Avoid use this technic
To get information from a thread, use rather Rashad's solution (Flag) or mksoft's (PostEvent)

Re: How to refresh?
Posted: Sun Jun 20, 2021 2:06 am
by platy
Thank you all for your contributions - much appreciated.