1

I am trying to create a GUI that communicates with a RS232 serial object. I'll present an analogous scenario to the problem that I am facing. I want to create a frame with 2 buttons, Start and Stop. The start button calls the 'foo' function:

status = True

def foo():
   n = 0
   while(getStatus()):
       print n
       n += 1
       sleep(0)

This foo function keeps running until I press stop.

def getStatus():
   return status

def stop():
   status = False

I understand Tkinter is single-threaded and once I press 'Start', the GUI will freeze. I know this is possible with the after function, but i strictly want to use threading. Is this possible with threading? If so can you please provide a sample code? Thank you.

Aasam Tasaddaq
  • 645
  • 4
  • 13
  • 23
  • I don't quite see your issue, simply start a thread (thread.threading) and have it check the status. Protect status by a lock/semaphore and you will be fine. I don't know about an atomic set in python which would work in your case. SInce you don't want to update the gui there is no difference to starting a thread from the console. – ted Aug 27 '12 at 19:35
  • @ted: I am not sure what all that meant. I am very new to GUI coding. Could you please point me to some useful links/docs if not a sample code? – Aasam Tasaddaq Aug 27 '12 at 19:38
  • if i have time i will try to put something together tonight if no one awnsered till then. Sorry I can't do it earlier, I have to take a look at it though since I did not do to much threading with python yet – ted Aug 28 '12 at 07:21

1 Answers1

1

here is some (not yet perfect) code:

What is missing/broken, but you did not ask for this, I added links:

  • It does not use locks => the calls to set might brake since they can occur at the same time. read the docs (this is quite easy)
  • It updates the gui from another thread. see 1 2
  • possibly more (not a threading guru)

Also for stopping threads look here

import time
import tkinter
from tkinter import ttk
import threading  

#gui
root = tkinter.Tk()
root.title("Threading demo")

status = tkinter.StringVar()
elapsed = tkinter.StringVar()
error = tkinter.StringVar()

#thread
class timer(threading.Thread):
    def __init__(self):
        super().__init__()
        self.stopped = False
        #your code here, don't need init if you have no code



    def run(self):
        status.set('running')

        while not self.isStopped():
            time.sleep(1)

            try:
                oldtime = int(elapsed.get())
            except ValueError:
                oldtime = 0

            elapsed.set(oldtime+1)

        status.set('stopped')
        time.sleep(2)

    def isStopped(self):
        return self.stopped



    def stop(self):
        self.stopped = True



#starts/stops thread (manages it)
class threadedOp(object):
    def __init__(self):
        self.thread = None


    def run(self):
        if self.thread == None:
            self.thread = timer()
            status.set('starting')
            self.thread.start()
        else:
            error.set('Thread already running')


    def stop(self):
        if self.thread != None:
            status.set('stopping')
            self.thread.stop()
            self.thread.join()
            error.set('Join complete')
            self.thread = None
        else:
            error.set('No thread to stop')

op = threadedOp()

#remaining gui
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(tkinter.N, tkinter.W, tkinter.E, tkinter.S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)

ttk.Label(mainframe, textvariable=elapsed).grid(column=1, row=1, sticky=(tkinter.W, tkinter.E))
ttk.Label(mainframe, textvariable=status).grid(column=2, row=1, sticky=(tkinter.W, tkinter.E))
ttk.Label(mainframe, textvariable=error).grid(column=1, row=3, sticky=(tkinter.W, tkinter.E))
ttk.Button(mainframe, text="Start", command=op.run).grid(column=1, row=2, sticky=tkinter.W)
ttk.Button(mainframe, text="Stop", command=op.stop).grid(column=2, row=2, sticky=tkinter.W)

root.mainloop()
Community
  • 1
  • 1
ted
  • 4,791
  • 5
  • 38
  • 84
  • Thank you. I was able to run your code after some editions. However, when i hit the start button, it prints a messages saying that the super() method needs one argument and none is given. What argument is super supposed to have in the timer class? – Aasam Tasaddaq Aug 29 '12 at 17:05
  • 1
    Are you running python 2.x? This was written for python 3. FOr instance the `tkinter` module used to have a capital `T` in 2.x I believe. If that is the case [super(see the docs)](http://docs.python.org/library/functions.html#super) excepts actually two arguments to be used in the way it is used here, the class name of which we want super, and instance to bind the super object to. so the line would read: `super(timer, self).__init__()`. With that the advantages of super are gone and you can alternatively write `threading.Thread.__init__(self)`, however I like super(familiarize with it for py3) – ted Aug 29 '12 at 18:29
  • Yes, I am running 2.x so had to change some of the syntax. Thanks again – Aasam Tasaddaq Aug 29 '12 at 19:31