I’m working on a wxPython application that does some data processing after a user clicks on a button. It is not possible to estimate how long this processing takes, so I use a wx.ProgressDialog as a progress tracker by calling Pulse(). Of course what I had to figure out was how to call Pulse() continuously until the data processing completes, which is a problem that allowed me to give Python threading my first try. I’m posting the code I use to solicit input on my approach, as you will see that there’s a little hack involving time.sleep as usually the program will crash due to segfaults involving wxPython processes if I don’t give it a pause. I’m happy enough with inserting a little pause, but I was wondering if someone might suggest a more elegant approach as this was my first attempt at working with threads. I did try a few things using thread locks, but those didn’t work as consistently as using the time.sleep hack. thanks for any comments.
platform: linux kernel 2.6.25, 64bit intel dual core
wxPython 2.8.8.0
user clicks on an OK button in a wx.Dialog window *
if dlg.ShowModal() == wx.ID_OK:
progress = progress_dialog(title='Processing) # returns a Thread (see below)
progress.start()
dlg.load_data() # this starts the data processing, which will return here once completed
progress.destroy()
time.sleep(1.0) # this is the hack I put in to slow things down a tad bit - without this, the program will usually crash
dlg.Destroy() # I think this is what will cause segfaults most of the time if I don't throw in a pause first to let the progress thread shut down completely
I'm working on a wxPython application that does some data processing after a user clicks on a button. It is not possible to estimate how long this processing takes, so I use a wx.ProgressDialog as a progress tracker by calling Pulse(). Of course what I had to figure out was how to call Pulse() continuously until the data processing completes, which is a problem that allowed me to give Python threading my first try. I'm posting the code I use to solicit input on my approach, as you will see that there's a little hack involving time.sleep as usually the program will crash due to segfaults involving wxPython processes if I don't give it a pause. I'm happy enough with inserting a little pause, but I was wondering if someone might suggest a more elegant approach as this was my first attempt at working with threads. I did try a few things using thread locks, but those didn't work as consistently as using the time.sleep hack. thanks for any comments.
I would recommend looking at the wxPython demo for how it does it. There's also this helpful wiki entry: LongRunningTasks - wxPyWiki
There was also some discussion on something like this last week, so browsing the archives is always a good idea.
thanks for the suggestion Robin - I’m trying to implement it using wxTimer (first time with it) but despite trying quite a few things, I never get an event raised by wx.EVT_TIMER (I included a print statement in the event handler and nothing was ever printed). I just see a ProgressDialog box but there is no pulsing, and then the box is destroyed once the processing is completed. I must be missing the point - maybe I have to thread the timer?
** want to start processing data
progress = progress_dialog(self, ‘Processing’) # self is a wx.Panel
processing data using fxns that are not part of wxPython
once done, return here
progress.destroy()
class progress_dialog: # I created a class so I can use it anywhere in my code
def init(self, gui, title):
self.progress = wx.ProgressDialog(title)
self.timer = wx.Timer(gui, -1)
On Mon, Jul 14, 2008 at 12:25 PM, Robin Dunn robin@alldunn.com wrote:
Paul Hartley wrote:
I’m working on a wxPython application that does some data processing after a user clicks on a button. It is not possible to estimate how long this processing takes, so I use a wx.ProgressDialog as a progress tracker by calling Pulse(). Of course what I had to figure out was how to call Pulse() continuously until the data processing completes, which is a problem that allowed me to give Python threading my first try. I’m posting the code I use to solicit input on my approach, as you will see that there’s a little hack involving time.sleep as usually the program will crash due to segfaults involving wxPython processes if I don’t give it a pause. I’m happy enough with inserting a little pause, but I was wondering if someone might suggest a more elegant approach as this was my first attempt at working with threads. I did try a few things using thread locks, but those didn’t work as consistently as using the time.sleep hack. thanks for any comments.
You should not create or modify any GUI component directly from your worker thread. This is simply unsafe and will cause problems. Instead you should either send events from the thread and allow them to be processed in the gui thread, or you can use wx.CallAfter from the worker thread to cause some callable object to be called in the context of the gui thread.
It sounds like you are not able to hook into your long running task to cause it to periodically send events or use wx.CallAfter. In that case the best thing to do is to simply start a timer in your gui and have the timer’s event handler call Pulse, and then stop the timer when your long running task is complete. Whatever you do the ultimate goal should be to not block the GUI’s main loop (which time.sleep will do) so it can continue to send events and update windows.
The above will create and start a timer to cause the OnTimer() method
to be called every 1 second or so.
- Josiah
···
On Mon, Jul 14, 2008 at 3:48 PM, Paul Hartley <phartley@gmail.com> wrote:
On Mon, Jul 14, 2008 at 12:25 PM, Robin Dunn <robin@alldunn.com> wrote:
Paul Hartley wrote:
I'm working on a wxPython application that does some data processing
after a user clicks on a button. It is not possible to estimate how long
this processing takes, so I use a wx.ProgressDialog as a progress tracker by
calling Pulse(). Of course what I had to figure out was how to call Pulse()
continuously until the data processing completes, which is a problem that
allowed me to give Python threading my first try. I'm posting the code I
use to solicit input on my approach, as you will see that there's a little
hack involving time.sleep as usually the program will crash due to segfaults
involving wxPython processes if I don't give it a pause. I'm happy enough
with inserting a little pause, but I was wondering if someone might suggest
a more elegant approach as this was my first attempt at working with
threads. I did try a few things using thread locks, but those didn't work
as consistently as using the time.sleep hack. thanks for any comments.
You should not create or modify any GUI component directly from your
worker thread. This is simply unsafe and will cause problems. Instead you
should either send events from the thread and allow them to be processed in
the gui thread, or you can use wx.CallAfter from the worker thread to cause
some callable object to be called in the context of the gui thread.
It sounds like you are not able to hook into your long running task to
cause it to periodically send events or use wx.CallAfter. In that case the
best thing to do is to simply start a timer in your gui and have the timer's
event handler call Pulse, and then stop the timer when your long running
task is complete. Whatever you do the ultimate goal should be to not block
the GUI's main loop (which time.sleep will do) so it can continue to send
events and update windows.
thanks for the suggestion Robin - I'm trying to implement it using wxTimer
(first time with it) but despite trying quite a few things, I never get an
event raised by wx.EVT_TIMER (I included a print statement in the event
handler and nothing was ever printed). I just see a ProgressDialog box but
there is no pulsing, and then the box is destroyed once the processing is
completed. I must be missing the point - maybe I have to thread the timer?
** want to start processing data
progress = progress_dialog(self, 'Processing') # self is a wx.Panel
## processing data using fxns that are not part of wxPython
## once done, return here
progress.destroy()
class progress_dialog: # I created a class so I can use it anywhere in my
code
def __init__(self, gui, title):
self.progress = wx.ProgressDialog(title)
self.timer = wx.Timer(gui, -1)
self.Bind(wx.EVT_TIMER, self.pulse)
self.timer.Start(100)