Problems with using queue in Tkinter application

Peter Otten __peter__ at web.de
Sat Jul 4 04:21:13 EDT 2009


Icarus wrote:

> I'm working on a serial protocol analyzer in python.  We have an
> application written by someone else in MFC but we need something that
> is cross platform.  I intended to implement the GUI portion in Tkinter
> but am having trouble.
> 
> The idea is that I will read messages from the serial port and output
> them to a Tkinter Text object initially.  Eventually it will have
> other functionality but that's it for the short term.  I've written
> this little test app to experiment with putting things on the GUI via
> a Queue which is polled by the Tkinter loop.
> 
> On some machines this code works fine and I get whatever I type in
> displayed in the Text widget.  On others I get errors like this as
> soon as I start it running.
> 
> error in background error handler:
> out of stack space (infinite loop?)
>     while executing
> "::tcl::Bgerror {out of stack space (infinite loop?)} {-code 1 -level
> 0 -errorcode NONE -errorinfo {out of stack space (infinite loop?)
>     while execu..."
> 
> 
> I don't understand why on some machines it works exactly as expected
> and on others it acts the same way Tkinter does when I call functions
> directly from outside the Tkinter thread.  Does anyone have any
> suggestions?  The full code as appended below.  Thanks in advance.
> 
> [code]
> 
> import Queue
> 
> class functionQueue:
> 
>     def __init__(self, root = None, timeout = 250):
> 
>         self.functionQueue = Queue.Queue()
>         self.root = root
>         self.timeout = timeout
> 
>         if(self.root):
>             self.pop_function(root)
> 
> 
>     def pop_function(self, root = None):
> 
>         try:
>             funcArgList = self.functionQueue.get(block = False)
>         except Queue.Empty:
>             pass
>         else:
>             try:
>                 funcArgList[0](*funcArgList[1])
>             except:
>                 try:
>                     print "Failed to call function", funcArgList[0]
>                 except:
>                     print "Failed to call function"
> 
>         if(root):
>             root.after(self.timeout, lambda: self.pop_function
> (self.root))
> 
>     def add_function(self, function, argList):
> 
>         try:
>             self.functionQueue.put([function, argList])
>         except:
>             pass
> 
> 
> if( __name__ == '__main__'):
> 
>     import Tkinter
>     import thread
> 
>     text = Tkinter.Text()
>     text.pack()
> 
>     myQueue = functionQueue(text, 50)
> 
>     def gui_loop():
>         try:
>             text.mainloop()
>         except:
>             import os
>             os._exit(1)
> 
>     thread.start_new_thread(text.mainloop, ())
> 
>     while(True):
>         usrInput = raw_input()
> 
>         if(usrInput == "-1"):
>             import os
>             os._exit(0)
> 
>         myQueue.add_function(text.insert, ['end', usrInput + "\n"])
>         myQueue.add_function(text.see, ['end'])
> 
> [/code]

I can make it work over here by putting the UI into the main thread, as 
suggested by http://effbot.org/zone/tkinter-threads.htm:

import Queue
import Tkinter
import threading

class FunctionQueue:
    # unchanged

def input_loop():
    while True:
        try:
            usrInput = raw_input()
        except EOFError:
            break
        myQueue.add_function(text.insert, ['end', usrInput + "\n"])
        myQueue.add_function(text.see, ['end'])
    myQueue.add_function(text.quit, [])

if __name__ == '__main__':
    text = Tkinter.Text()
    text.pack()

    myQueue = FunctionQueue(text, 50)
    threading.Thread(target=input_loop).start()
    text.mainloop()

Peter





More information about the Python-list mailing list