Hello Guido van Rossum, when your source code looks like this:
from tkinter import Tk, Label from threading import Thread import time def thread(): for i in range(10): time.sleep(1) t.after(0, lambda: l.configure(text = str(i))) t = Tk() l = Label(t) l.pack() th = Thread(target = thread) th.start() t.mainloop() then it works under Windows. Thank you for Python, Nicco Kunzmann Am 06.11.2013 18:17, schrieb Andreas Ostermann: > Hi, > > some time ago we were very unhappy about the same issue. > > Coming from Java I tried to port the "invokeLater" idea of swing to > python which leads me to the following code (including dynamic Proxy > objects for easier communication between the stuff in the background > and the tk world) [the Background thread in this example is doing some > polling, I later used an own implementation for a Queue which let me > interrupt the get... but as your problem is the tk world: there is no > busy waiting in this example] > > import Tkinter > import Queue > import uuid > import threading > import thread > > # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### > ### ### ### ### ### ### ### ### ### ### > > class BackgroundListener (threading.Thread) : > def __init__(self): > threading.Thread.__init__(self) > self.queue = Queue.Queue() > self.cancel = threading.Event() > def invokeLater(self, delegate): > self.queue.put(delegate) > def interrupt(self) : > self.cancel.set() > def run(self): > while not self.cancel.isSet() : > try : > delegate = self.queue.get(timeout=0.5) > if not self.cancel.isSet() : # don't call if already finished > ! > delegate() > except Queue.Empty : > pass > > class TkListener : > def __init__(self, tk) : > self.queue = Queue.Queue() > self.tk = tk > self.event = "<<%s>>" % uuid.uuid1() > tk.bind(self.event, self.invoke) > def invokeLater(self, delegate) : > self.queue.put(delegate) > self.tk.event_generate(self.event, when='tail') > def invoke(self, event) : > try : > while True : > delegate = self.queue.get(block=False) > delegate() > except Queue.Empty : > pass > > # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### > ### ### ### ### ### ### ### ### ### ### > > class Delegate : > def __init__(self, real, name, args, kwargs) : > self.real = real > self.name = name > self.args = args > self.kwargs = kwargs > def __call__(self) : > method = getattr(self.real, self.name) > apply(method, self.args, self.kwargs) > > class Delegator : > def __init__(self, listener, real, name) : > self.listener = listener > self.real = real > self.name = name > def __call__(self, *args, **kwargs) : > delegate = Delegate(self.real, self.name, args, kwargs) > self.listener.invokeLater(delegate) > > class Proxy : > def __init__(self, listener, real) : > self.listener = listener > self.real = real > self.cache = {} > def __getattr__(self, name) : > try : > delegator = self.cache[name] > except KeyError : > delegator = Delegator(self.listener, self.real, name) > self.cache[name] = delegator > return delegator > > # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### > ### ### ### ### ### ### ### ### ### ### > > class MyTkinterObject: > def __init__(self, tk): > frame = Tkinter.Frame(tk) > self.quitButton = Tkinter.Button(frame, text="QUIT", fg="red", > command=frame.quit) > self.quitButton.pack(side=Tkinter.LEFT) > self.helloButton = Tkinter.Button(frame, text="Hello") > self.helloButton.pack(side=Tkinter.LEFT) > self.hello2Button = Tkinter.Button(frame, text="Hello2", > command=self.trigger2) > self.hello2Button.pack(side=Tkinter.LEFT) > frame.pack() > def register(self, myBackgroundObject) : > self.helloButton.bind("<Button-1>", myBackgroundObject.trigger) > def trigger(self, callback) : > print "%s - Front hello" % thread.get_ident() > callback() > def trigger2(self) : > print "%s - Front hello" % thread.get_ident() > > class MyBackgroundObject : > def __init__(self, listener): > self.proxy = Proxy(listener, self) > def register(self, myTkinterObject) : > self.myTkinterObject = myTkinterObject > def trigger(self, event) : > print "%s - Back hello - %s" % (thread.get_ident(), event) > self.myTkinterObject.trigger(self.proxy.callback) > def callback(self) : > print "%s - Back bye" % thread.get_ident() > > # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### > ### ### ### ### ### ### ### ### ### ### > > def main() : > root = Tkinter.Tk() > > tkListener = TkListener(root) > backgroundListener = BackgroundListener() > > myTkinterObject = MyTkinterObject(root) > myBackgroundObject = MyBackgroundObject(backgroundListener) > > myTkinterObject.register(myBackgroundObject.proxy) > myBackgroundObject.register(Proxy(tkListener, myTkinterObject)) > > backgroundListener.start() > root.mainloop() > backgroundListener.interrupt() > > # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### > ### ### ### ### ### ### ### ### ### ### > > if __name__ == "__main__": > main() > > brgds, > > -- Jan Übernickel (via Andreas) > > 2013/11/6 Guido van Rossum <gu...@python.org>: >> After many years I'm trying my hands at Tkinter again, and things have >> changed... >> >> I'm using Python 2.7 here, but it doesn't look like 3.x changes the issue. >> Tcl/Tk version is 8.5, on Mac OS (10.8). >> >> I've got a situation where a background thread is doing I/O and wants to >> wake up the Tk event loop. It seems the established wisdom (e.g. >> http://code.activestate.com/recipes/82965-threads-tkinter-and-asynchronous-io/) >> is to have the Tk event loop wake up every e.g. 100 msec and check a queue >> or other state shared with the thread. This works, but makes me worry that >> my app will be draining battery power even when no data from the bg thread >> is forthcoming. >> >> I've tried other things: >> >> - createfilehandler: This says it cannot work when Tcl/Tk is threaded and it >> will be removed in Python 3 anyway. >> >> - The bg thread can use after_idle() or after() to run a command on the Tk >> object; this works, but it doesn't seem to wake up the Tk main loop -- the >> command usually only runs when I cause a UI event to be generated (e.g. >> selecting the window). >> >> What other solutions could I try? I really don't like the "after(100, >> <repeat>)" solution. >> >> -- >> --Guido van Rossum (python.org/~guido) >> >> _______________________________________________ >> Tkinter-discuss mailing list >> Tkinter-discuss@python.org >> https://mail.python.org/mailman/listinfo/tkinter-discuss >> > _______________________________________________ > Tkinter-discuss mailing list > Tkinter-discuss@python.org > https://mail.python.org/mailman/listinfo/tkinter-discuss
_______________________________________________ Tkinter-discuss mailing list Tkinter-discuss@python.org https://mail.python.org/mailman/listinfo/tkinter-discuss