[Pythonmac-SIG] Threading with Tkinter on OSX - Bus Error

Tony Lownds tony@lownds.com
Sat, 20 Jul 2002 12:36:36 -0700


Hi Peter,

>I know that some people have previously mentioned that Tk needs to 
>have all GUI stuff on one thread, but in the example below, that is 
>the case

I don't think it is the case. When your program gets to 
time.sleep(3), it's not in the main thread; the next line calls 
delegate.message("testing"), which ends up calling Tk.

Calling Tk from a Python-created thread that Tk knows nothing about 
on Aqua Tkinter causes crashes to ensue.

>Any help would be greatly appreciated!

Here is your script adjusted to use a Queue. This way the GUI calls 
really only happen in one thread. I wish I had a more general 
solution.

-Tony

# --------------------------------------------------------------------------
# -- buserr.py -------------------------------------------------------------

from Tkinter import *
from threading import *
import time
import Queue

# Class frm ----------------------------------------------------------------
class frm(Frame):

	# Builtins ---------------------------------------------------------
	def __init__(self, parent=None):
		self.queue = Queue.Queue(10)
		Frame.__init__(self, master=parent)
		if ((parent.__class__ == Toplevel) or 
(parent.__class__ == Tk)):
			parent.title("Testing")
			parent.geometry("400x300")
		self.pack()
		self.__createGUI()

		# Start the message thread
		msgTh = Thread(target=msgThread, args=(self,))
		msgTh.start()

	# Public Interface --------------------------------------------------
	def message(self, msg):
		"""Add the given message to the text; may fail with "Full" """
		self.queue.put((self.__message, msg))

	def runloop(self):
		"""similar to mainloop, but also checks our Queue"""
		while 1:
			try:
				dispatch = self.queue.get_nowait()
			except Queue.Empty:
				root.tk.dooneevent()
			else:
				apply(dispatch[0], dispatch[1:])

	# Private Methods ---------------------------------------------------
	def __createGUI(self):
		"""Create all the GUI components"""
		self.txtFoo = Text(self)
		self.txtFoo.pack(side=TOP, fill=X, expand=1, padx=10)

	def __message(self, msg):
		"""Add the given message to the text"""
                 currText = self.txtFoo.get(1.0, END)
                 newText = currText + msg
		print "About to explode..."
                 self.txtFoo.insert(END, newText)
		print "We never get here!"


# Thread routine ------------------------------------------------------------
def msgThread(delegate):
	time.sleep(3)
	delegate.message("Testing")


# Main ----------------------------------------------------------------------
root = Tk()
gui = frm(root)
gui.runloop()