如何将异步方法绑定到 Tkinter 中的击键? [英] How to bind async method to a keystroke in Tkinter?
问题描述
考虑以下示例:
导入异步将 tkinter 作为 tk 导入类应用程序(tk.Tk):def __init__(self):super().__init__()self.create_widgets()self._configure_bindings() # 我相信这是不可能的# 如果方法需要,则执行此操作# 也是异步的def create_widgets(self):经过def _configure_bindings(self):self.bind('', self.spam) # 正确的方法是什么?# 这个方法也需要异步吗?异步定义垃圾邮件(自我,事件):等待 self.do_something()异步定义 do_something():经过async def run_tk(root):尝试:为真:根.更新()等待 asyncio.sleep(.01)除了 tk.TclError 作为 e:如果应用程序已被销毁"不在 e.args[0] 中:增加如果 __name__ == '__main__':应用程序 = 应用程序()asyncio.get_event_loop().run_until_complete(run_tk(app))
在 tkinter 中将异步方法绑定到击键的正确方法是什么?我试过类似的东西:
self.bind('', self.spam)self.bind('', await self.spam)self.bind('', await self.spam())self.bind('', lambda 事件:等待 self.spam(event))
...以及一堆其他组合,但无济于事.
tkinter
本身是异步的,这要归功于事件循环,after
方法和 绑定.
但是,如果您尝试使用 asyncio
也有可能,但首先让我们考虑一下您尝试过的内容.
您的第一次尝试显然失败了,因为您尝试将 spam
作为通用函数调用,而它是 coroutine
.您的其他尝试比第一次更正确,但是 await coroutine
或 yield from coroutine
只能用于从另一个协程启动协程,因此它再次失败.>
因此,启动该野兽的正确方法是调度其执行,并使用不言自明的方法 ensure_future
(或旧的 async
,这只是一个已弃用的别名.
试试这个例子:
导入异步将 tkinter 作为 tk 导入类应用程序(tk.Tk):def __init__(self):super().__init__()self._configure_bindings()def _configure_bindings(self):self.bind('', lambda 事件:asyncio.ensure_future(self.spam(event)))异步定义垃圾邮件(自我,事件):等待 self.do_something()等待 asyncio.sleep(2)print('%s 执行了!' % self.spam.__name__)async def do_something(self):print('%s 执行了!' % self.do_something.__name__)async def run_tk(root):尝试:为真:根.更新()等待 asyncio.sleep(.01)除了 tk.TclError 作为 e:如果应用程序已被销毁"不在 e.args[0] 中:增加如果 __name__ == '__main__':应用程序 = 应用程序()asyncio.get_event_loop().run_until_complete(run_tk(app))
另外,我认为值得一提的是这个 问题,因为您使用了 update
方法.
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, 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.
这篇关于如何将异步方法绑定到 Tkinter 中的击键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!