Threading module question

Andrew Gregory andrew.gregory at npl.co.uk
Thu Jul 15 06:51:41 EDT 2004


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()



More information about the Python-list mailing list