samedi 9 août 2014

python - affichant les progrès avec wxPython - Stack Overflow


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