Reputation: 46403
I want to launch a big processing (that involves loading lots of things/files into memory, and is 1 minute long) when something has been double-clicked with wxPython
:
class MyPanel(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, ...)
# some code here
self.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick)
def OnDoubleClick(self, event):
BigAndLongProcessing()
DoSomething() # this code will code be called only 1 minute after !
# here even if there is no code, I imagine that it would be
# good to return here quickly in order to finish the wx.EVT_LEFT_DCLICK
# event instead of waiting 1 minute...
How to deal with such a situation, for which a GUI event should launch a long processing BigAndLongProcessing()
?
I thought about :
def OnDoubleClick(self, event):
wx.CallLater(1, BigAndLongProcessing)
but I don't find it very clean because :
wx.CallLater
will probably create a new thread (timer?) and I don't know if starting a new thread by this way for this operation is a good idea. Anyway if I want to start a new thread, shouldn't I start it with threading
instead of CallLater
?BigAndLongProcessing()
won't be handled by the main thread, so it's more complicated then...What's a clean framework for such a situation ?
Upvotes: 0
Views: 114
Reputation: 69242
Long running processes should be put in a thread so as not to disrupt GUI interactions. That is, you probably want your code to look more like this:
import threading
def OnDoubleClick(self, event):
t = threading.Thread(target=BigAndLongProcessing)
t.start()
DoSomething()
def CallMeWhenThreadIsCompleted(self):
print "BigAndLongProcessing has completed"
Note, here, that DoSomething
will be called right after the thread is started, not when it's completed.
If you want to communicate from the long thread back to the main thread, that's when you'd use CallAfter
. So, for example, to do something when the BigAndLongProcessing is about to finish, then put wx.CallAfter(CallMeWhenThreadIsCompleted)
in the long thread to communicate back to the main thread.
Upvotes: 1
Reputation: 14685
I think that you will appreciate reading about various solutions to this question here.
I think that wx.CallLater()
is not really what you want: it's like using an almost-suitable tool for a job that it's not really intended for. Your bullets 1 & 2 point to this fact.
Even if you used CallLater to get some processing outside of the call flow in your OnClick handler, you are still going to be consuming time that wx can't be using for having the GUI active, and you have to deal with that anyhow ... using one of the methods I have pointed to.
The link I pointed to offers threading, wx.Yield(), and EVT_IDLE as ways to do this.
wx.Yield() might be most attractive to you if you want to keep exception handling feeling as close to normal as possible.
With threading and EVT_IDLE, you will need to communicate the effects of exceptions to your main processing using something like pubsub (or wx.CallAfter)
If you use wx.Yield(), don't forget that the rest of your code can get executed at any time that you Yield - including theoretically the handler you are in.
Upvotes: 1