Consider the following example:
import asyncio
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.create_widgets()
self._configure_bindings() # I believe it is not possible
# to do this if the method needs
# to be async as well
def create_widgets(self):
pass
def _configure_bindings(self):
self.bind('<F5>', self.spam) # what's the proper way?
# does this method need to be async as well?
async def spam(self, event):
await self.do_something()
async def do_something():
pass
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))
What is the proper way to bind async method to a keystroke in tkinter? I've tried something like:
self.bind('<F5>', self.spam)
self.bind('<F5>', await self.spam)
self.bind('<F5>', await self.spam())
self.bind('<F5>', lambda event: await self.spam(event))
...and a bunch of other combinations, but to no avail.
tkinter
itself is asynchronous thanks to event loop, theafter
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 acoroutine
. Your other tries are more correct than a first, butawait coroutine
oryield 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 oldasync
, which is just a deprecated alias).Try this example:
Also, I think that it's worth to mention this question, since you use an
update
method.