I'm hoping someone will be able to give me a hand displaying the progress for a long running task using wxPython.
I currently have a function, which is invoked by a button, and executes 5 other functions e.g.
def sum(self, event):
self.processSents()
self.processWords()
self.repSents()
self.measSim()
self.selCont()
I would like to display a progress bar while these functions are being executed, as the program sometimes hangs which isn't ideal.
A lot of the solutions I've looked at suggest threading, but I'm pretty inexperienced with threads in Python, and my attempts are getting me nowhere fast. I'm not sure for example, if the dialog should be in the thread, the executing code, or both.
My current attempt is as follows:
def sum(self, event):
progress = wx.ProgressDialog("sum in progress", "please wait", maximum=100, parent=self, style=wx.PD_SMOOTH|wx.PD_AUTO_HIDE)
self.Start(self.DoWork, progress)
progress.ShowModal()
def Start(func, *args):
thread = threading.Thread(target=func, args=args)
thread.setDaemon(True)
thread.start()
def DoWork(self, progress):
for i in range(101):
ex.CallAfter(progress.Update, i)
time.sleep(0.2)
self.processSents()
self.processWords()
self.repSents()
self.measSim()
self.selCont()
wx.CallAfter(progress.Destroy)
The solutions I've looked at so far are:
Updating a wxPython progress bar after calling app.MainLoop()
How to thread wxPython progress bar
How Can I Safely Manage wxPython Progress Dialog Threading?
http://wiki.wxpython.org/LongRunningTasks
Any help or advice would be appreciated as I'm pretty lost :(
Thanks
Chris
Updated to working version (combination of Jerry's response combined with wx.Yield() as recommended by Corley
def sum(self, event):
progress = wx.ProgressDialog("sum in progress", "please wait", maximum=100, parent=self, style=wx.PD_SMOOTH|wx.PD_AUTO_HIDE)
self.processSents()
percent = 20
progress.Update(percent)
self.processWords()
percent += 20
progress.Update(percent)
// repSends, measSim and selCont omitted to save space
progress.Destroy()
wx.Yield() is called from within each function e.g.
def processSents(self):
// some long running process
wx.Yield()
// end of long running process
A possibly simpler option is just to call wx.Yield()
periodically in your code; this allows the GUI to refresh/process inputs. Of course, nothing else will run, but it does allow your progress bar to update properly.
The progress bar should probably be a global, or passed to the subfunctions, so that it can update the progress as it goes.
1) Thread DoWork
would be created when you click the button.
2) In DoWork
, another thread showProgress
would be created to display the progress dialog
3)In DoWork
, doSomething
simulate some time-consuming thing
4) Aonther thread updateProgress
would be created before each doSomething
in this sample to avoid the progress bar freeze, but actually you should call self.progress.Update
to update the progress bar while your sum progress
import wx
import threading
import time
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None)
panel = wx.Panel(self)
btn1 = wx.Button(panel, label="test1")
btn1.Bind(wx.EVT_BUTTON, self.onButton1)
btn2 = wx.Button(panel, label="test2")
btn2.Bind(wx.EVT_BUTTON, self.onButton2)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(btn1)
sizer.Add(btn2)
panel.SetSizer(sizer)
self.maxPercent = 100
self.percent = 0
def onButton1(self, evt):
self.StartThread(self.DoWork1)
def onButton2(self, evt):
self.StartThread(self.DoWork2)
def StartThread(self, func, *args):
thread = threading.Thread(target=func, args=args)
thread.setDaemon(True)
thread.start()
def showProgress(self):
self.progress = wx.ProgressDialog("sum in progress", "please wait", maximum=self.maxPercent, parent=self, style=wx.PD_SMOOTH|wx.PD_AUTO_HIDE)
def destoryProgress(self):
self.progress.Destroy()
def updateProgress(self, percent):
keepGoing = True
time.sleep(1)
while keepGoing and self.percent < percent:
self.percent += 1
(keepGoing, skip) = self.progress.Update(self.percent)
time.sleep(0.1)
def doSomething(self, take_time, taskPercent, say_something):
time.sleep(take_time)
(keepGoing, skip) = self.progress.Update(taskPercent, say_something+" done!")
def DoWork1(self):
self.StartThread(self.showProgress)
taskPercent = 25
self.StartThread(self.updateProgress, taskPercent)
self.doSomething(5, taskPercent, "1st")
taskPercent +=25
self.StartThread(self.updateProgress, taskPercent)
self.doSomething(5, taskPercent, "2nd")
taskPercent +=25
self.StartThread(self.updateProgress, taskPercent)
self.doSomething(5, taskPercent, "3rd")
taskPercent +=25
self.StartThread(self.updateProgress, taskPercent)
self.doSomething(5, taskPercent, "4th")
self.destoryProgress()
def DoWork2(self):
self.StartThread(self.showProgress)
taskPercent = 25
self.doSomething(5, taskPercent, "1st")
taskPercent +=25
self.doSomething(5, taskPercent, "2nd")
taskPercent +=25
self.doSomething(5, taskPercent, "3rd")
taskPercent +=25
self.doSomething(5, taskPercent, "4th")
self.destoryProgress()
if __name__ == '__main__':
app = wx.App(0)
frame = MyFrame()
frame.Show()
app.MainLoop()
I'm hoping someone will be able to give me a hand displaying the progress for a long running task using wxPython.
I currently have a function, which is invoked by a button, and executes 5 other functions e.g.
def sum(self, event):
self.processSents()
self.processWords()
self.repSents()
self.measSim()
self.selCont()
I would like to display a progress bar while these functions are being executed, as the program sometimes hangs which isn't ideal.
A lot of the solutions I've looked at suggest threading, but I'm pretty inexperienced with threads in Python, and my attempts are getting me nowhere fast. I'm not sure for example, if the dialog should be in the thread, the executing code, or both.
My current attempt is as follows:
def sum(self, event):
progress = wx.ProgressDialog("sum in progress", "please wait", maximum=100, parent=self, style=wx.PD_SMOOTH|wx.PD_AUTO_HIDE)
self.Start(self.DoWork, progress)
progress.ShowModal()
def Start(func, *args):
thread = threading.Thread(target=func, args=args)
thread.setDaemon(True)
thread.start()
def DoWork(self, progress):
for i in range(101):
ex.CallAfter(progress.Update, i)
time.sleep(0.2)
self.processSents()
self.processWords()
self.repSents()
self.measSim()
self.selCont()
wx.CallAfter(progress.Destroy)
The solutions I've looked at so far are:
Updating a wxPython progress bar after calling app.MainLoop()
How to thread wxPython progress bar
How Can I Safely Manage wxPython Progress Dialog Threading?
http://wiki.wxpython.org/LongRunningTasks
Any help or advice would be appreciated as I'm pretty lost :(
Thanks
Chris
Updated to working version (combination of Jerry's response combined with wx.Yield() as recommended by Corley
def sum(self, event):
progress = wx.ProgressDialog("sum in progress", "please wait", maximum=100, parent=self, style=wx.PD_SMOOTH|wx.PD_AUTO_HIDE)
self.processSents()
percent = 20
progress.Update(percent)
self.processWords()
percent += 20
progress.Update(percent)
// repSends, measSim and selCont omitted to save space
progress.Destroy()
wx.Yield() is called from within each function e.g.
def processSents(self):
// some long running process
wx.Yield()
// end of long running process
A possibly simpler option is just to call wx.Yield()
periodically in your code; this allows the GUI to refresh/process inputs. Of course, nothing else will run, but it does allow your progress bar to update properly.
The progress bar should probably be a global, or passed to the subfunctions, so that it can update the progress as it goes.
1) Thread DoWork
would be created when you click the button.
2) In DoWork
, another thread showProgress
would be created to display the progress dialog
3)In DoWork
, doSomething
simulate some time-consuming thing
4) Aonther thread updateProgress
would be created before each doSomething
in this sample to avoid the progress bar freeze, but actually you should call self.progress.Update
to update the progress bar while your sum progress
import wx
import threading
import time
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None)
panel = wx.Panel(self)
btn1 = wx.Button(panel, label="test1")
btn1.Bind(wx.EVT_BUTTON, self.onButton1)
btn2 = wx.Button(panel, label="test2")
btn2.Bind(wx.EVT_BUTTON, self.onButton2)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(btn1)
sizer.Add(btn2)
panel.SetSizer(sizer)
self.maxPercent = 100
self.percent = 0
def onButton1(self, evt):
self.StartThread(self.DoWork1)
def onButton2(self, evt):
self.StartThread(self.DoWork2)
def StartThread(self, func, *args):
thread = threading.Thread(target=func, args=args)
thread.setDaemon(True)
thread.start()
def showProgress(self):
self.progress = wx.ProgressDialog("sum in progress", "please wait", maximum=self.maxPercent, parent=self, style=wx.PD_SMOOTH|wx.PD_AUTO_HIDE)
def destoryProgress(self):
self.progress.Destroy()
def updateProgress(self, percent):
keepGoing = True
time.sleep(1)
while keepGoing and self.percent < percent:
self.percent += 1
(keepGoing, skip) = self.progress.Update(self.percent)
time.sleep(0.1)
def doSomething(self, take_time, taskPercent, say_something):
time.sleep(take_time)
(keepGoing, skip) = self.progress.Update(taskPercent, say_something+" done!")
def DoWork1(self):
self.StartThread(self.showProgress)
taskPercent = 25
self.StartThread(self.updateProgress, taskPercent)
self.doSomething(5, taskPercent, "1st")
taskPercent +=25
self.StartThread(self.updateProgress, taskPercent)
self.doSomething(5, taskPercent, "2nd")
taskPercent +=25
self.StartThread(self.updateProgress, taskPercent)
self.doSomething(5, taskPercent, "3rd")
taskPercent +=25
self.StartThread(self.updateProgress, taskPercent)
self.doSomething(5, taskPercent, "4th")
self.destoryProgress()
def DoWork2(self):
self.StartThread(self.showProgress)
taskPercent = 25
self.doSomething(5, taskPercent, "1st")
taskPercent +=25
self.doSomething(5, taskPercent, "2nd")
taskPercent +=25
self.doSomething(5, taskPercent, "3rd")
taskPercent +=25
self.doSomething(5, taskPercent, "4th")
self.destoryProgress()
if __name__ == '__main__':
app = wx.App(0)
frame = MyFrame()
frame.Show()
app.MainLoop()
0 commentaires:
Enregistrer un commentaire