How to bind async method to a keystroke in Tkinter?

六眼飞鱼酱① 提交于 2019-12-06 04:46:24

tkinter itself is asynchronous thanks to event loop, the after method and the bindings.

However, if you trying to stick with asyncio it's also possible, but first let's consider what you tried.

Your first try is obviously a fail, because you trying to call spam as a generic function, when it's a coroutine. Your other tries are more correct than a first, but await coroutine or yield from coroutine can be used to start a coroutine from another coroutine only, so it fails again.

So the proper way of start that beast is a scheduling of its execution with a self-explanatory method ensure_future (or old async, which is just a deprecated alias).

Try this example:

import asyncio
import tkinter as tk


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self._configure_bindings()

    def _configure_bindings(self):
        self.bind('<F5>', lambda event: asyncio.ensure_future(self.spam(event)))

    async def spam(self, event):
        await self.do_something()
        await asyncio.sleep(2)
        print('%s executed!' % self.spam.__name__)

    async def do_something(self):
        print('%s executed!' % self.do_something.__name__)

async def run_tk(root):
    try:
        while True:
            root.update()
            await asyncio.sleep(.01)
    except tk.TclError as e:
        if "application has been destroyed" not in e.args[0]:
            raise

if __name__ == '__main__':
    app = App()
    asyncio.get_event_loop().run_until_complete(run_tk(app))

Also, I think that it's worth to mention this question, since you use an update method.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!