How To Update Progress Bar As Well As Download File Using Multi-threading
I'm trying to download files using the Request module using Multi threading and simultaneously need to Update a Progress bar as well. But while doing so, whenever I press submit bu
Solution 1:
With apologies to Mike
for highjacking his code for a skeleton, here is a rough version using urlretrieve
and a wxPython event
to do the updating.
import os
import wx
import time
from threading import Thread
from urllib.request import FancyURLopener
from urllib.request import urlopen
import wx.lib.newevent
urlretrieve = FancyURLopener().retrieve
progress_event, EVT_PROGRESS_EVENT = wx.lib.newevent.NewEvent()
classDownloadThread(Thread):
def__init__(self, parent, url, fsize):
"""Constructor"""
Thread.__init__(self)
self.fsize = fsize
self.url = url
self.parent = parent
self.start()
defrun(self):
local_fname = os.path.basename(self.url)
urlretrieve(self.url, local_fname, self.reporthook)
defreporthook(self,blocknum, blocksize, totalsize):
readsofar = blocknum * blocksize
if totalsize > 0:
percent = int((readsofar / totalsize) * 100)
else: # total size is unknown
percent = 0
evt = progress_event(count=percent)
#Send back current count for the progress bartry:
wx.PostEvent(self.parent, evt)
except: # The parent frame has probably been destroyedpassclassMyPanel(wx.Panel):
def__init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
self.lbl = wx.StaticText(self, label="Download URL:")
self.dl_txt = wx.TextCtrl(self)
btn = wx.Button(self, label="Download")
self.gauge = wx.Gauge(self, -1, range=100)
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
dl_sizer = wx.BoxSizer(wx.HORIZONTAL)
dl_sizer.Add(self.dl_txt, 1, wx.EXPAND|wx.ALL, 5)
dl_sizer.Add(btn, 0, wx.ALL, 5)
self.main_sizer.Add(dl_sizer, 0, wx.EXPAND)
self.main_sizer.Add(self.lbl, 0, wx.ALL|wx.CENTER, 5)
self.main_sizer.Add(self.gauge, 0, wx.ALL|wx.EXPAND, 5)
self.SetSizer(self.main_sizer)
#Bind to the progress event issued by the thread
self.Bind(EVT_PROGRESS_EVENT, self.OnProgress)
btn.Bind(wx.EVT_BUTTON, self.OnDownload)
defOnDownload(self, event):
url = self.dl_txt.GetValue()
self.lbl.SetLabel(os.path.basename(url))
try:
header = urlopen(url)
fsize = int(header.headers['Content-Length'])
# start thread
d_thread = DownloadThread(self, url, fsize)
while d_thread.isAlive():
time.sleep(0.1)
wx.GetApp().Yield()
continue# Finished re-set
self.dl_txt.SetValue("")
self.lbl.SetLabel("Download URL:")
self.gauge.SetValue(0)
except Exception as e:
print ("Error: ", e)
defOnProgress(self, event):
""""""
self.gauge.SetValue(event.count)
classDownloaderFrame(wx.Frame):
def__init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Downloader", size=(800, 400))
panel = MyPanel(self)
self.Show()
if __name__ == "__main__":
app = wx.App(False)
frame = DownloaderFrame()
app.MainLoop()
Solution 2:
I wrote a tutorial on this topic a while back.
Here's the code:
import requests
import os
import wx
import wx.lib.scrolledpanel as scrolled
from threading import Thread
from wx.lib.pubsub import pub
classDownloadThread(Thread):
"""Downloading thread"""def__init__(self, gnum, url, fsize):
"""Constructor"""
Thread.__init__(self)
self.fsize = fsize
self.gnum = gnum
self.url = url
self.start()
defrun(self):
"""
Run the worker thread
"""
local_fname = os.path.basename(self.url)
count = 1whileTrue:
if os.path.exists(local_fname):
tmp, ext = os.path.splitext(local_fname)
cnt = "(%s)" % count
local_fname = tmp + cnt + ext
count += 1else:
break
req = requests.get(self.url, stream=True)
total_size = 0print(local_fname)
withopen(local_fname, "wb") as fh:
for byte in req.iter_content(chunk_size=1024):
if byte:
fh.write(byte)
fh.flush()
total_size += len(byte)
if total_size < self.fsize:
wx.CallAfter(pub.sendMessage,
"update_%s" % self.gnum,
msg=total_size)
wx.CallAfter(pub.sendMessage,
"update_%s" % self.gnum,
msg=self.fsize)
classMyGauge(wx.Gauge):
""""""def__init__(self, parent, range, num):
"""Constructor"""
wx.Gauge.__init__(self, parent, range=range)
pub.subscribe(self.updateProgress, "update_%s" % num)
defupdateProgress(self, msg):
""""""
self.SetValue(msg)
classMyPanel(scrolled.ScrolledPanel):
""""""def__init__(self, parent):
"""Constructor"""
scrolled.ScrolledPanel.__init__(self, parent)
self.data = []
self.download_number = 1# create the sizers
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
dl_sizer = wx.BoxSizer(wx.HORIZONTAL)
# create the widgets
lbl = wx.StaticText(self, label="Download URL:")
self.dl_txt = wx.TextCtrl(self)
btn = wx.Button(self, label="Download")
btn.Bind(wx.EVT_BUTTON, self.onDownload)
# layout the widgets
dl_sizer.Add(lbl, 0, wx.ALL|wx.CENTER, 5)
dl_sizer.Add(self.dl_txt, 1, wx.EXPAND|wx.ALL, 5)
dl_sizer.Add(btn, 0, wx.ALL, 5)
self.main_sizer.Add(dl_sizer, 0, wx.EXPAND)
self.SetSizer(self.main_sizer)
self.SetAutoLayout(1)
self.SetupScrolling()
defonDownload(self, event):
"""
Update display with downloading gauges
"""
url = self.dl_txt.GetValue()
try:
header = requests.head(url)
fsize = int(header.headers["content-length"]) / 1024
sizer = wx.BoxSizer(wx.HORIZONTAL)
fname = os.path.basename(url)
lbl = wx.StaticText(self, label="Downloading %s" % fname)
gauge = MyGauge(self, fsize, self.download_number)
sizer.Add(lbl, 0, wx.ALL|wx.CENTER, 5)
sizer.Add(gauge, 0, wx.ALL|wx.EXPAND, 5)
self.main_sizer.Add(sizer, 0, wx.EXPAND)
self.Layout()
# start thread
DownloadThread(self.download_number, url, fsize)
self.dl_txt.SetValue("")
self.download_number += 1except Exception as e:
print("Error: ", e)
classDownloaderFrame(wx.Frame):
""""""def__init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Downloader", size=(800, 400))
panel = MyPanel(self)
self.Show()
if __name__ == "__main__":
app = wx.App(False)
frame = DownloaderFrame()
app.MainLoop()
Post a Comment for "How To Update Progress Bar As Well As Download File Using Multi-threading"