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