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