Tkinter bloquea Python cuando se carga un icono y tk.mainloop está en un hilo

Aquí está el caso de prueba …

import Tkinter as tk import thread from time import sleep if __name__ == '__main__': t = tk.Tk() thread.start_new_thread(t.mainloop, ()) # t.iconbitmap('icon.ico') b = tk.Button(text='test', command=exit) b.grid(row=0) while 1: sleep(1) 

Este código funciona. Descomenta la línea t.iconbitmap y se bloquea. Re-organizarlo de la manera que desee; se bloqueará.

¿Cómo evito que tk.mainloop bloquee la GIL cuando hay un icono presente?

El objective es win32 y Python 2.6.2.

Creo que no deberías ejecutar el bucle principal en un hilo diferente. AFAIK, el bucle principal debe ejecutarse en el mismo hilo que creó el widget.

Los kits de herramientas de la GUI con los que estoy familiarizado (Tkinter, .NET Windows Forms) son de esa manera: puede manipular la GUI desde un solo hilo.

En Linux, su código genera una excepción:

 self.tk.mainloop (n)
 RuntimeError: Llamando a Tcl desde un apartamento diferente

Una de las siguientes opciones funcionará (sin subprocesos adicionales):

 if __name__ == '__main__': t = tk.Tk() t.iconbitmap('icon.ico') b = tk.Button(text='test', command=exit) b.grid(row=0) t.mainloop() 

Con hilo extra:

 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) 

Si necesita comunicarse con tkinter desde fuera del subproceso de tkinter, le sugiero que configure un temporizador que verifique la cola de trabajo.

Aquí hay un ejemplo:

 import Tkinter as tk import thread from time import sleep import Queue request_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 = None def 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)