Example of StatusbarProgress Update
Example of StatusbarProgress Update
Can anyone give me a explanation or, preferably, a quick commented example, of how you update a StatusbarProgress gadget when copying a file source to destination? Creating the gadget, according to the Purebasic documentation looks simple enough but I can’t figure out how use it to show the progress when using CopyFile().
Thanks
Thanks
http://www.oldtimeradiotoday.com - Listen to or download classic old time radio broadcasts.
- microdevweb
- Enthusiast
- Posts: 179
- Joined: Fri Jun 13, 2014 9:38 am
- Location: Belgique
Re: Example of StatusbarProgress Update
Hi Columbo,
a small example
a small example
Code: Select all
; example of status bar
Global max = 1000 ; max value of status bar
Enumeration
#MAIN_FORM
#STATUS_BAR
#TEXT
EndEnumeration
Procedure THR_increment(*para)
Protected n
Repeat
n + 1
SetGadgetText(#TEXT,"progress "+Str(n)+" on "+Str(max))
StatusBarProgress(#STATuS_BAR,0,n,#PB_StatusBar_BorderLess,0,max)
Delay(20)
Until n > =max
MessageRequester("Information","The work is done",#PB_MessageRequester_Info)
CloseWindow(#MAIN_FORM)
End
EndProcedure
Procedure start()
OpenWindow(#MAIN_FORM,0,0,200,50,"Working",#PB_Window_ScreenCentered)
TextGadget(#TEXT,10,10,180,30,"")
CreateStatusBar(#STATUS_BAR,WindowID(#MAIN_FORM))
AddStatusBarField(#PB_Ignore) ; take all size
CreateThread(@THR_increment(),0)
EndProcedure
start()
Repeat
WaitWindowEvent()
ForEver
Use Pb 5.73 lst and Windows 10
my mother-language isn't english, in advance excuse my mistakes.
my mother-language isn't english, in advance excuse my mistakes.
Re: Example of StatusbarProgress Update
Dont update gui from thread. Crash prone.
Use postevent to instruct main event loop to update gui.
Use postevent to instruct main event loop to update gui.
Re: Example of StatusbarProgress Update
Thank you microdevweb. There are no comments in the code but I see how you are creating the StatusBarProgress Gadget. I'm just not sure how to connect it to the copying of a file using CopyFile()? I am assuming that it should know how large the file is and somehow determine how much of the total file has been copied and update the StatusBarProgress Gadget accordingly but that is where I am lost.
http://www.oldtimeradiotoday.com - Listen to or download classic old time radio broadcasts.
Re: Example of StatusbarProgress Update
Hi John.Columbo wrote:...not sure how to connect it to the copying of a file using CopyFile()? ... somehow determine how much of the total file has been copied and update the StatusBarProgress Gadget accordingly...
In my experience, the CopyFile() function tends to be a little blocking and provides no updates in its process. An ideal alternative would be to manually copy the file with the ReadData() / WriteData() functions, allowing greater control of the process and progress. Here's an example which performs quite comparably to the system function, complete with progress updates (with detailed comments as requested -

Code: Select all
CompilerIf Not #PB_Compiler_Thread
compiler_error.s = "Please enable threadsafe option in menu:" + #CRLF$ +
"Compiler > Compiler Options > [X] Create threadsafe executable"
MessageRequester("File Copy", compiler_error)
End
CompilerEndIf
; values for custom post events should
; start from #PB_Event_FirstCustomValue
Enumeration #PB_Event_FirstCustomValue
; events to be posted from copy thread to
; update main thread of states & progress
#File_Copy_Started
#File_Copy_Progress
#File_Copy_Complete
#File_Copy_Incomplete
#File_Copy_Error
; gadget & window identifiers
#mainWindow = 0
#progressLabel = 0
#progressBar
#startCopyButton
#abortCopyButton
; file handles
#sourceFile = 0
#destinationFile
; number of bytes to read & write at a time
#copyChunkSize = 1048576
EndEnumeration
; global flags to facilitate thread termination
Global copyThread, threadQuit
; files are selected outside the thread, so they are
; declared as globals to be accessible by the thread
Global.s sourceFile, destinationFile
; drop-in file copy procedure with progress
Procedure FileCopyProgress(threadData)
; open source file for reading
If ReadFile(#sourceFile, sourceFile)
; capture source file length to calculate progress
sourceFileLen = Lof(#sourceFile)
destinationFileLen = sourceFileLen
; create the destination file or overwrite if exists
If CreateFile(#destinationFile, destinationFile)
; create a memory buffer to hold the read data
*fileCopyBuffer = AllocateMemory(#copyChunkSize)
; notify main thread that copy process has started
PostEvent(#File_Copy_Started)
; loop until copied data is zero or thread termination flag is set
While destinationFileLen > 0 And Not threadQuit
; read #copyChunkSize data into memory buffer
ReadData(#sourceFile, *fileCopyBuffer, #copyChunkSize)
; write #copyChunkSize data into destination file
WriteData(#destinationFile, *fileCopyBuffer, #copyChunkSize)
; decrease remaining data to be written
destinationFileLen - #copyChunkSize
; calculate the percentage of the progress (basic math)
progress.d = ((sourceFileLen - destinationFileLen) / sourceFileLen) * 100
; notify main thread of progress percentage (rounded-off integer value only)
PostEvent(#File_Copy_Progress, 0, 0, 0, Int(progress))
Wend
; free allocated memory & close destination file
FreeMemory(*fileCopyBuffer)
CloseFile(#destinationFile)
; notify main thread of completion state based on percentage
If progress < 100
PostEvent(#File_Copy_Incomplete)
Else
PostEvent(#File_Copy_Complete)
EndIf
Else
; notify main thread of destination file-creation error
PostEvent(#File_Copy_Error, 0, 0, 0, #destinationFile)
EndIf
; close source file
CloseFile(#sourceFile)
Else
; notify main thread of source file-opening error
PostEvent(#File_Copy_Error, 0, 0, 0, #sourceFile)
EndIf
EndProcedure
; selecting files before starting the copy thread
Procedure StartFileCopy()
; start the copy process if the thread is not active
If Not IsThread(copyThread)
; select source & destination files
sourceFile = OpenFileRequester("Select file to copy", "", "*.*", 0)
If sourceFile <> ""
destinationFile = SaveFileRequester("Select destination path & filename", "", "*.*", 0)
If destinationFile <> ""
threadQuit = #False
copyThread = CreateThread(@FileCopyProgress(), 0)
EndIf
EndIf
EndIf
EndProcedure
; show/hide gadgets (repetitive calls)
Procedure DisplayProgress(show)
HideGadget(#startCopyButton, show)
HideGadget(#progressBar, show ! #True)
HideGadget(#progressLabel, show ! #True)
HideGadget(#abortCopyButton, show ! #True)
SetGadgetState(#progressBar, 0)
EndProcedure
wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
OpenWindow(#mainWindow, 0, 0, 400, 200, "Copy File Progress", wFlags)
TextGadget(#progressLabel, 0, 30, 400, 40, "Copying 0%...", #PB_Text_Center)
ProgressBarGadget(#progressBar, 10, 70, 380, 40, 0, 100)
ButtonGadget(#startCopyButton, 100, 80, 200, 40, "SELECT FILE TO COPY")
ButtonGadget(#abortCopyButton, 100, 130, 200, 40, "ABORT")
DisplayProgress(#False)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
If IsThread(copyThread)
; if thread is active terminate thread
threadQuit = #True
Else
; if thread is not active terminate app
appQuit = #True
EndIf
; thread notifies that copy process has started
Case #File_Copy_Started
DisplayProgress(#True)
; thread notifies of copy progress
Case #File_Copy_Progress
; get the progress percentage sent by the thread
progress = EventData()
; update UI only if percentage is different from last notification
If progress <> lastProgress
lastProgress = progress
SetGadgetState(#progressBar, progress)
SetGadgetText(#progressLabel, "Copying " + Str(progress) + "%...")
EndIf
; thread notifies that copy has completed
Case #File_Copy_Complete
message.s = sourceFile + #CRLF$ + " copied to " + #CRLF$ + destinationFile
MessageRequester("File Copy", message)
DisplayProgress(#False)
; thread notifies that copy was aborted
Case #File_Copy_Incomplete
MessageRequester("File Copy", "File copy aborted!")
DisplayProgress(#False)
; thread notifies of copy error
Case #File_Copy_Error
; get the copy error sent by the thread
error = EventData()
If error = #sourceFile
errorMessage$ = "Error opening source file!"
Else
errorMessage$ = "Error creating destination file!"
EndIf
MessageRequester("File Copy", errorMessage$)
; gadget handlers
Case #PB_Event_Gadget
Select EventGadget()
; start the file copy process
Case #startCopyButton
StartFileCopy()
; abort copy process and terminate the thread
Case #abortCopyButton
If IsThread(copyThread)
threadQuit = #True
EndIf
EndSelect
EndSelect
Until appQuit
1. Added the threadsafe check as suggested by Marc56us.
2. Removed the file selection from the thread as it was crashing on MacOS, as highlighted by Mindphazer.
Last edited by TI-994A on Wed Mar 11, 2020 3:52 pm, edited 2 times in total.
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel 

- netmaestro
- PureBasic Bullfrog
- Posts: 8451
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
Re: Example of StatusbarProgress Update
I made one too. You don't need it since TI-994A already did it but I worked on it so you get it.
Replace a$ with the path of a large file on your drive and b$ with its copied name to test:
Replace a$ with the path of a large file on your drive and b$ with its copied name to test:
Code: Select all
#UpdateStatus = #PB_Event_FirstCustomValue
Global a$, b$, threadfinished.i=#False, tid.i=0
a$ = "d:\movies\broadcast news.mp4"
b$ = "c:\movies\broadcast news.mp4"
Procedure Thread(void)
threadfinished=#False
If FileSize(b$) = 0 Or FileSize(b$) = -1
If OpenFile(0, a$)
If CreateFile(1, b$)
totalbytes.q = FileSize(a$)
chunksize.i = totalbytes/100
lastchunk.i = totalbytes%100
*chunkholder = AllocateMemory(chunksize)
For i=1 To 100
ReadData(0, *chunkholder, chunksize)
WriteData(1, *chunkholder, chunksize)
PostEvent(#UpdateStatus,#PB_Ignore,#PB_Ignore,#PB_Ignore, i)
Delay(1)
Next
If lastchunk
ReadData(0, *chunkholder, lastchunk)
WriteData(1, *chunkholder, lastchunk)
EndIf
threadfinished=#True
CloseFile(0)
CloseFile(1)
MessageRequester("", "Copy Finished!")
PostEvent(#UpdateStatus,#PB_Ignore,#PB_Ignore,#PB_Ignore, 0)
EndIf
EndIf
Else
MessageRequester("", "File exists!")
PostEvent(#UpdateStatus,#PB_Ignore,#PB_Ignore,#PB_Ignore, 0)
EndIf
EndProcedure
Procedure ButtonHandler()
If Not IsThread(tid)
tid = CreateThread(@Thread(), 0)
DisableGadget(1, 1)
EndIf
EndProcedure
Procedure UpdateStatus()
StatusBarProgress(0,0, EventData())
If EventData()=0
DisableGadget(1, 0)
EndIf
EndProcedure
OpenWindow(0,0,0,640,480,"",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CreateStatusBar(0, WindowID(0))
AddStatusBarField(640)
StatusBarProgress(0,0,0,#PB_StatusBar_BorderLess,0,100)
BindEvent(#UpdateStatus, @UpdateStatus())
ButtonGadget(1, 270, 250, 100, 20, "Copy Now")
BindGadgetEvent(1, @ButtonHandler())
Repeat:Until WaitWindowEvent() = #PB_Event_CloseWindow
Last edited by netmaestro on Thu Mar 12, 2020 2:16 am, edited 2 times in total.
BERESHEIT
- microdevweb
- Enthusiast
- Posts: 179
- Joined: Fri Jun 13, 2014 9:38 am
- Location: Belgique
Re: Example of StatusbarProgress Update
That right with another language like Java, but with Pb i never don't have any problem. Just active the thread option of compilatorRinzwind wrote:Dont update gui from thread. Crash prone.
Use postevent to instruct main event loop to update gui.
Use Pb 5.73 lst and Windows 10
my mother-language isn't english, in advance excuse my mistakes.
my mother-language isn't english, in advance excuse my mistakes.
Re: Example of StatusbarProgress Update
That reminds me; make sure to select the Create threadsafe executable option under the Compiler > Compiler Options menu whenever using threads, like in theses example.microdevweb wrote:...active the thread option of compilator
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel 

Re: Example of StatusbarProgress Update

Code: Select all
EnableExplicit
CompilerIf Not #PB_Compiler_Thread
CompilerError "Need Compiler Options > [X] Create threadsafe executable"
CompilerEndIf
However, with SSD disks you often won't have time to see anything unless you have a huge file.
There is also an API that displays the Windows copy window with a progress bar and optionally a flow chart.
(but I don't know where)

- Mindphazer
- Enthusiast
- Posts: 460
- Joined: Mon Sep 10, 2012 10:41 am
- Location: Savoie
Re: Example of StatusbarProgress Update
Hi microdevwebmicrodevweb wrote:That right with another language like Java, but with Pb i never don't have any problem. Just active the thread option of compilatorRinzwind wrote:Dont update gui from thread. Crash prone.
Use postevent to instruct main event loop to update gui.
Your code crashes on MacOS (even with thread safe activated); it does not on Windows
MacBook Pro 16" M4 Pro - 24 Gb - MacOS 15.4.1 - Iphone 15 Pro Max - iPad at home
...and unfortunately... Windows at work...
...and unfortunately... Windows at work...
Re: Example of StatusbarProgress Update
Thanks Syed and netmaestro. Very much appreciated. I'll look at both examples.
Cheers!
Cheers!
http://www.oldtimeradiotoday.com - Listen to or download classic old time radio broadcasts.
Re: Example of StatusbarProgress Update
The Module ThreadToGUI is for this... See Signatur 

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
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Re: Example of StatusbarProgress Update
Well commented Syed, thank you so much. Just one clarification,... Can you explain the "Thread" stuff? I know what a thread is in a forum post but what is it in a Purebasic program?
Thanks.
Thanks.
http://www.oldtimeradiotoday.com - Listen to or download classic old time radio broadcasts.
Re: Example of StatusbarProgress Update
@Columbo:
About threads in PureBasic:
https://www.purebasic.com/documentation ... index.html
Here I have also a module from the forum member @ts-soft: CopyDirEx.pbi
About threads in PureBasic:
https://www.purebasic.com/documentation ... index.html
Here I have also a module from the forum member @ts-soft: CopyDirEx.pbi

Why OpenSource should have a license :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (syntax color scheme) :: RegEx-Engine (compiles RegExes to NFA/DFA)
Manjaro Xfce x64 (Main system) :: Windows 10 Home (VirtualBox) :: Newest PureBasic version
- netmaestro
- PureBasic Bullfrog
- Posts: 8451
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
Re: Example of StatusbarProgress Update
Lieutenant, a thread works like this: Say you have a procedure called Doit() that you call from your main loop. Your main loop stops executing until that procedure has finished and control is returned to it from the procedure. No good for long jobs. A thread is a procedure that executes alongside your main loop, running at the same time so your main loop can keep going, not stopping to wait for the procedure to finish. You often have a loop in a thread procedure and if you do it's wise to make sure there's a Delay(1) in it otherwise it'll hog the whole cpu. That's basically it in a nutshell, it's not complicated or difficult at all.
BERESHEIT