Tkinter locks Python when an icon is loaded and tk.mainloop is in a thread Tkinter locks Python when an icon is loaded and tk.mainloop is in a thread tkinter tkinter

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)