Domanda

Ecco il banco di prova ...

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)

Questo codice funziona. Rimuovere il commento dalla linea t.iconbitmap e si blocca. Ri-organizzare in qualsiasi modo che ti piace; si blocca.

Come posso evitare tk.mainloop bloccare la GIL quando c'è un'icona presente?

L'obiettivo è win32 e Python 2.6.2.

È stato utile?

Soluzione

Credo che non si deve eseguire il ciclo principale su un thread diverso. AFAIK, il ciclo principale deve essere eseguito sullo stesso filo che ha creato il gadget.

I toolkit GUI che mi è familiare (Tkinter, NET Windows Forms) sono in questo modo: È possibile manipolare la GUI da un solo thread

.

In Linux, il codice solleva un'eccezione:

self.tk.mainloop(n)
RuntimeError: Calling Tcl from different appartment

Uno dei seguenti funzionerà (nessun thread aggiuntivi):

if __name__ == '__main__':
    t = tk.Tk()
    t.iconbitmap('icon.ico')

    b = tk.Button(text='test', command=exit)
    b.grid(row=0)

    t.mainloop()

Con filo in più:

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)

Se avete bisogno di fare comunicare con tkinter da fuori discussione Tkinter, vi consiglio di impostare un timer che controlla una coda di lavoro.

Ecco un esempio:

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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top