Tkinter locks Python when an icon is loaded and tk.mainloop is in a thread
I believe you should not execute the main loop on a different thread. AFAIK, the main loop should be executed on the same thread that created the widget.
The GUI toolkits that I am familiar with (Tkinter, .NET Windows Forms) are that way: You can manipulate the GUI from one thread only.
On Linux, your code raises an exception:
self.tk.mainloop(n)RuntimeError: Calling Tcl from different appartment
One of the following will work (no extra threads):
if __name__ == '__main__': t = tk.Tk() t.iconbitmap('icon.ico') b = tk.Button(text='test', command=exit) b.grid(row=0) t.mainloop()
With extra thread:
def threadmain(): t = tk.Tk() t.iconbitmap('icon.ico') b = tk.Button(text='test', command=exit) b.grid(row=0) t.mainloop()if __name__ == '__main__': thread.start_new_thread(threadmain, ()) while 1: sleep(1)
If you need to do communicate with tkinter from outside the tkinter thread, I suggest you set up a timer that checks a queue for work.
Here is an example:
import Tkinter as tkimport threadfrom time import sleepimport Queuerequest_queue = Queue.Queue()result_queue = Queue.Queue()def submit_to_tkinter(callable, *args, **kwargs): request_queue.put((callable, args, kwargs)) return result_queue.get()t = Nonedef threadmain(): global t def timertick(): try: callable, args, kwargs = request_queue.get_nowait() except Queue.Empty: pass else: print "something in queue" retval = callable(*args, **kwargs) result_queue.put(retval) t.after(500, timertick) t = tk.Tk() t.configure(width=640, height=480) b = tk.Button(text='test', name='button', command=exit) b.place(x=0, y=0) timertick() t.mainloop()def foo(): t.title("Hello world")def bar(button_text): t.children["button"].configure(text=button_text)def get_button_text(): return t.children["button"]["text"]if __name__ == '__main__': thread.start_new_thread(threadmain, ()) trigger = 0 while 1: trigger += 1 if trigger == 3: submit_to_tkinter(foo) if trigger == 5: submit_to_tkinter(bar, "changed") if trigger == 7: print submit_to_tkinter(get_button_text) sleep(1)