I've written a Tkinter application (Windows) that uses the threading
module, which I've reduced to the test case below (apologies if it's a
bit long). Using the Queue module to pass messages the callable
function in ClassDoRun can be started and interrupted via 'Start' and
'Abort' buttons. Having started then interrupted the function I
expected to be able to execute the function again from the beginning
using the 'Start' button - but I get an error message saying that the
thread is already running, even though the function has been exited.
How do I fix this?
Andrew.
# threaddemo.py
#
# Python 2.3.4 (requires Tix)
#
import threading, Queue, Tix, time
# In the full program the function below
# controls various instruments and collects data.
# A much-shortened version is given here.
class ClassDoRun:
def __init__(self, CS):
self.CS = CS
def __call__(self):
CS = self.CS
for i in range(10):
CS.Counter.set(i) # write a value for display in GUI
time.sleep(1.0)
if CS.AbortRun: break
class CommonStuff: # to provide two-way common access to variables
# and functions by GUI and 'run' threads
def __init__(self, root):
self.root=root
self.root.title("threaddemo.py, vs 12-Jul-2004")
self.frame = Tix.Frame(root)
self.frame.bind("<Destroy>",self.CleanUp)
self.AbortRun=0
self.Counter=Tix.IntVar()
def myquit(self):
self.root.destroy()
def CleanUp(self, event):
print "Cleaning up after Tkinter closed"
def ButtonBoxWidget(Fquit, Frun, Fabort, frame):
butbox = Tix.ButtonBox(frame, orientation=Tix.HORIZONTAL)
butbox.add('start', text='Start', underline=0, width=6,
command=Frun)
butbox.add('abort', text='Abort', underline=0, width=6,
command=Fabort)
butbox.add('quit', text='Quit', underline=0, width=6,
command=Fquit)
return butbox
class MainWidget(CommonStuff, Tix.TixWidget):
def __init__(self, CS, Qput):
self.CS = CS
self.Qput = Qput
self.Lcounter = Tix.Label(CS.frame, textvariable=CS.Counter)
self.Lcounter.grid(row=0, column=0, pady=5)
self.butbox = ButtonBoxWidget(CS.myquit, self.SendRunMessage,
self.SendAbortMessage, CS.frame)
self.butbox.grid(row=1, column=0)
def SendRunMessage(self):
self.Qput('run')
def SendAbortMessage(self):
self.Qput('abort')
class Application:
def __init__(self, CS):
self.CS = CS
self.Q = Queue.Queue() # Pass messages to separate run
# thread via the queue Q
self.displayedwidget=MainWidget(CS, self.Q.put)
CS.frame.pack()
self.RunnableObject = ClassDoRun(CS)
self.thread = threading.Thread(target=self.RunnableObject)
self.poll()
def MessageQueue(self): # messages e.g. Run, Abort
self.CS.root.update()
while self.Q.qsize():
try:
msg = self.Q.get(0)
if msg=="abort": self.CS.AbortRun = 1
if msg=="run":
self.CS.AbortRun=0
if not self.thread.isAlive(): self.thread.start()
except Queue.Empty: pass
def poll(self):
#print self.thread.isAlive()
self.MessageQueue()
self.CS.root.after(100, self.poll)
if __name__ == '__main__':
root = Tix.Tk()
CS = CommonStuff(root)
mainWin = Application(CS)
root.mainloop() 3 1566
On 13 Jul 2004 07:40:14 -0700, an************@npl.co.uk (Andrew Gregory)
declaimed the following in comp.lang.python: expected to be able to execute the function again from the beginning using the 'Start' button - but I get an error message saying that the
Read the manual...
"""
start( )
Start the thread's activity.
This must be called at most once per thread object. It arranges for the
object's run() method to be invoked in a separate thread of control.
"""
Note the clause: "... once per thread object"
thread is already running, even though the function has been exited. How do I fix this?
As the old joke finishes: "Stop doing that"
I'd use a sequence of joining the dead thread, deleting it, and
creating a whole new thread object.
-- ================================================== ============ < wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG < wu******@dm.net | Bestiaria Support Staff < ================================================== ============ < Home Page: <http://www.dm.net/~wulfraed/> < Overflow Page: <http://wlfraed.home.netcom.com/> <
Solution: You cannot re-run a threaded function, but you can delete
the thread
a create a new one. I'm sure that I should have thought of that
before, but this is the first occasion that I've tried to use use
threads, and this was not obvious to me from the docs. I've posted the
code in case it's useful to others.
I know that it could be shortened, but it is a model for a much longer
script.
General comment: Writing Tkinter and Tix GUI applications is quite
easy most of the time, quite often I find that I can just copy and
paste from something that I've written before. It only becomes tricky
when programming something that you haven't tried before. What would
really help would be a good selection of examples (PYTHONCARD is quite
good in this respect). I know there are some (e.g. in the Tix
download), but more would help. Does anyone know any good sites for
examples?
# threaddemo.py
#
# Demonstrate a Tix GUI which can launch and interrupt
# a function in a separate thread.
#
# A. P. Gregory, 15th July 2004.
#
# Python 2.3.4 (requires Tix)
#
import threading, Queue, Tix, time
import tkFont
class ClassDoRun:
def __init__(self, CS):
self.CS = CS
CS.Counter.set('Press to start\ncountdown')
def __call__(self):
CS = self.CS
for i in range(0,10):
CS.Counter.set(str(10-i)+'/10') # write a value for
display in GUI
time.sleep(1.0)
if CS.AbortRun:
CS.Counter.set('Aborted\n(can re-start)')
return
CS.Counter.set('Bang!')
class CommonStuff: # to provide two-way common access to variables
# and functions by GUI and 'run' threads
def __init__(self, root):
self.root=root
self.root.title("threaddemo.py, vs 15-Jul-2004")
self.frame = Tix.Frame(root)
self.frame.bind("<Destroy>",self.CleanUp)
self.AbortRun=0
self.Counter=Tix.StringVar()
def myquit(self):
self.root.destroy()
def CleanUp(self, event):
print "Cleaning up after Tkinter closed"
class ButtonBoxWidget:
def __init__(self, Fquit, Frun, Fabort, frame):
butbox = Tix.ButtonBox(frame, orientation=Tix.HORIZONTAL)
self.butbox = butbox
butbox.add('start', text='Start', underline=0, width=6,
command=Frun)
butbox.add('abort', text='Abort', underline=0, width=6,
command=Fabort)
butbox.add('quit', text='Quit', underline=0, width=6,
command=Fquit)
def grid(self, **kwargs): self.butbox.grid(kwargs)
class MainWidget(CommonStuff, Tix.TixWidget):
def __init__(self, CS, Qput):
self.CS = CS
self.Qput = Qput
self.Lcounter = Tix.Label(CS.frame, textvariable=CS.Counter,
font=('Sans Serif', 16, 'bold'), fg='blue', bg='white', padx=16,
height=2, width=8)
self.Lcounter.grid(row=0, column=0, pady=15)
self.butbox = ButtonBoxWidget(CS.myquit, self.SendRunMessage,
self.SendAbortMessage, CS.frame)
self.butbox.grid(row=1, column=0)
def SendRunMessage(self):
self.Qput('run')
def SendAbortMessage(self):
self.Qput('abort')
class Application:
def __init__(self, CS):
self.CS = CS
self.Q = Queue.Queue() # Pass messages to separate run thread
via the queue Q
self.displayedwidget=MainWidget(CS, self.Q.put)
CS.frame.pack()
self.RunnableObject = ClassDoRun(CS)
self.thread = threading.Thread(target=self.RunnableObject)
self.poll()
def MessageQueue(self): # messages e.g. Run, Abort
self.CS.root.update()
while self.Q.qsize():
try:
msg = self.Q.get(0)
if msg=="abort": self.CS.AbortRun = 1
if msg=="run":
self.CS.AbortRun=0
if not self.thread.isAlive():
del self.thread # Cannot re-run
function,
# but can delete
thread
# and run as new.
self.thread = threading.Thread(
target=self.RunnableObject)
self.thread.start()
except Queue.Empty: pass
def poll(self):
#print self.thread.isAlive()
self.MessageQueue()
self.CS.root.after(100, self.poll)
if __name__ == '__main__':
root = Tix.Tk()
CS = CommonStuff(root)
mainWin = Application(CS)
root.mainloop()
In article <28**************************@posting.google.com >,
Andrew Gregory <an************@npl.co.uk> wrote: Solution: You cannot re-run a threaded function, but you can delete the thread a create a new one. I'm sure that I should have thought of that before, but this is the first occasion that I've tried to use use threads, and this was not obvious to me from the docs. I've posted the code in case it's useful to others.
Better answer: re-use the thread. Have the thread you create sitting on
a Queue, waiting for input.
--
Aahz (aa**@pythoncraft.com) <*> http://www.pythoncraft.com/
Barbara Boxer speaks for me: http://buffaloreport.com/2004/040713....marriage.html This discussion thread is closed Replies have been disabled for this discussion. Similar topics
19 posts
views
Thread by Jane Austine |
last post: by
|
13 posts
views
Thread by Varun |
last post: by
|
3 posts
views
Thread by David Harrison |
last post: by
|
6 posts
views
Thread by Matt Long |
last post: by
|
2 posts
views
Thread by Jason MacKenzie |
last post: by
|
2 posts
views
Thread by hecklar |
last post: by
|
4 posts
views
Thread by rh0dium |
last post: by
|
3 posts
views
Thread by Sparky |
last post: by
|
reply
views
Thread by Edwin.Madari |
last post: by
| | | | | | | | | | |