Issue with wxPython GUI
tarun
tarundevnani at gmail.com
Tue Nov 13 07:23:58 EST 2007
Thanks a lot Laszlo Nagy,
I used the following and it worked.
import time
from threading import *
import wx
# Button definitions
ID_START = wx.NewId()
ID_STOP = wx.NewId()
# Define notification event for thread completion
EVT_RESULT_ID = wx.NewId()
def EVT_RESULT(win, func):
"""Define Result Event."""
win.Connect(-1, -1, EVT_RESULT_ID, func)
class ResultEvent(wx.PyEvent):
"""Simple event to carry arbitrary result data."""
def __init__(self, data):
"""Init Result Event."""
wx.PyEvent.__init__(self)
self.SetEventType(EVT_RESULT_ID)
self.data = data
# Thread class that executes processing
class WorkerThread(Thread):
"""Worker Thread Class."""
def __init__(self, notify_window):
"""Init Worker Thread Class."""
Thread.__init__(self)
self._notify_window = notify_window
self._want_abort = 0
# This starts the thread running on creation, but you could
# also make the GUI thread responsible for calling this
self.start()
def run(self):
"""Run Worker Thread."""
# This is the code executing in the new thread. Simulation of
# a long process (well, 10s here) as a simple loop - you will
# need to structure your processing so that you periodically
# peek at the abort variable
for i in range(10):
time.sleep(1)
if self._want_abort:
# Use a result of None to acknowledge the abort (of
# course you can use whatever you'd like or even
# a separate event type)
wx.PostEvent(self._notify_window, ResultEvent(None))
return
# Here's where the result would be returned (this is an
# example fixed result of the number 10, but it could be
# any Python object)
wx.PostEvent(self._notify_window, ResultEvent(10))
def abort(self):
"""abort worker thread."""
# Method for use by main thread to signal an abort
self._want_abort = 1
# GUI Frame class that spins off the worker thread
class MainFrame(wx.Frame):
"""Class MainFrame."""
def __init__(self, parent, id):
"""Create the MainFrame."""
wx.Frame.__init__(self, parent, id, 'Thread Test')
# Dumb sample frame with two buttons
wx.Button(self, ID_START, 'Start', pos=(0,0))
wx.Button(self, ID_STOP, 'Stop', pos=(0,50))
self.status = wx.StaticText(self, -1, '', pos=(0,100))
self.Bind(wx.EVT_BUTTON, self.OnStart, id=ID_START)
self.Bind(wx.EVT_BUTTON, self.OnStop, id=ID_STOP)
# Set up event handler for any worker thread results
EVT_RESULT(self,self.OnResult)
# And indicate we don't have a worker thread yet
self.worker = None
def OnStart(self, event):
"""Start Computation."""
# Trigger the worker thread unless it's already busy
if not self.worker:
self.status.SetLabel('Starting computation')
self.worker = WorkerThread(self)
def OnStop(self, event):
"""Stop Computation."""
# Flag the worker thread to stop if running
if self.worker:
self.status.SetLabel('Trying to abort computation')
self.worker.abort()
def OnResult(self, event):
"""Show Result status."""
if event.data is None:
# Thread aborted (using our convention of None return)
self.status.SetLabel('Computation aborted')
else:
# Process results here
self.status.SetLabel('Computation Result: %s' % event.data)
# In either event, the worker is done
self.worker = None
class MainApp(wx.App):
"""Class Main App."""
def OnInit(self):
"""Init Main App."""
self.frame = MainFrame(None, -1)
self.frame.Show(True)
self.SetTopWindow(self.frame)
return True
if __name__ == '__main__':
app = MainApp(0)
app.MainLoop()
Thanks & Regards,
Tarun
On 11/13/07, Laszlo Nagy <gandalf at shopzeus.com> wrote:
>
> tarun írta:
> > Hi Laszlo Nagy,
> >
> > Thanks a lot.
> > But the issue over here is that how will the child thread acknowledge
> > the main thread that it has completed its task. For this I'll have to
> > set some flag in the child thread and poll for it in the main thread.
> > This will create a problem.
> What kind of problem, can you explain? Supposing your child (worker)
> thread created the output, I would do it this way (untested):
>
> class Child(threading.Thread):
> def __init__(self,output):
> self.stop_requested = threading.Event()
> self.stopped = threading.Event()
> self.output = output
> ....
>
> def run(self):
> try:
> while not self.stop_requested.isSet():
> # put your algorithm here
> ....
> # but check periodically if you need to abort the job.
> if self.stop_requested.isSet():
> break
> ...
> # when you have data, put into the output queue
> self.output.put( your_output )
> finally:
> self.stopped.set()
>
>
> -- And then, from the main thread, create the worker:
>
> self.queue = Queue()
> self.child = Child(self.queue)
>
> -- wxApp.OnIdle:
>
> if not self.queue.empty():
> data = self.queue.get()
> # display your data here, for example add to a text control.
>
> if self.child.stopped.isSet():
> add_log("Job compete") # tell the user what is going on
>
> And finally, you can have a button for stopping the script:
>
> def OnClick(self,event):
> self.child.stop_requested.set()
> add_log("stopping worker thread....") # tell the user what is going
> on
>
> > Any alternatives??
> First you should tell us what is the problem with using two threads.
>
> Regards,
>
> Laszlo
>
>
>
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20071113/9ae3d984/attachment.html>
More information about the Python-list
mailing list