Problems with using queue in Tkinter application

Icarus asm198 at gmail.com
Sat Jul 4 11:23:33 EDT 2009


On Jul 4, 3:21 am, Peter Otten <__pete... at web.de> wrote:
> 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 byhttp://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

Peter, thanks for the suggestion.  I tried your code exactly on my box
and I still get the same results.  As soon as I run the script and
every time I click on the Text box I get tcl::Bgerror ... just like I
mentioned above.  I'm fairly certain that I'm not calling Tkinter
functions from any other thread but it's acting as though I am as soon
as I create the input thread.
If I comment out the input loop thread everything is fine but of
course that's not terribly useful as a logging box.



More information about the Python-list mailing list