'''Proof of concept 2: integrate tkinter and async iterator. Terry Jan Reedy, 2016 July 19 Run with 'python -i' or from IDLE editor to keep tk window alive. This version uses async for loop and async timer to update tk label. See tkloop.py for other comments. ''' import asyncio as aio import tkinter as tk import datetime import threading # On Windows, need proactor for subprocess functions EventLoop = aio.SelectorEventLoop # Following gets aio.SelectorEventLoop # EventLoop = type(aio.get_event_loop()) class TkEventLoop(EventLoop): def __init__(self, root): self.root = root super().__init__() def run_forever(self): # copy with 1 new line for proof of concept """Run until stop() is called.""" self._check_closed() if self.is_running(): raise RuntimeError('Event loop is running.') self._set_coroutine_wrapper(self._debug) self._thread_id = threading.get_ident() try: while True: self._run_once() # can block indefinitely self.root.update() # new line if self._stopping: break finally: self._stopping = False self._thread_id = None self._set_coroutine_wrapper(False) root = tk.Tk() loop = TkEventLoop(root) aio.set_event_loop(loop) class atimer(): "Yield n or n+1 ticks (None) at intervals." def __init__(self, n, interval, tick0=False): "Yield initial tick if tick0." self.interval = interval self.tick0 = tick0 self.end_time = loop.time() + (n + .9) * interval async def __aiter__(self): return self async def __anext__(self): if self.tick0: self.tick0 = False return await aio.sleep(self.interval) if loop.time() <= self.end_time: return else: raise StopAsyncIteration def flipbg(widget, color): bg = widget['bg'] print('click', bg, loop.time()) widget['bg'] = color if bg == 'white' else 'white' async def display_date(n, interval): hello = tk.Label(root, text='Hello World', bg='white') flipper = tk.Button(root, text='Change hello background', bg='yellow', command=lambda: flipbg(hello, 'red')) label = tk.Label(root) hello.pack() flipper.pack() label.pack() root.update() async for tick in atimer(n, interval, tick0=True): print(datetime.datetime.now()) label['text'] = datetime.datetime.now() loop.run_until_complete(display_date(10, 1.0)) loop.close()