如何将异步方法绑定到 Tkinter 中的击键?
Posted
技术标签:
【中文标题】如何将异步方法绑定到 Tkinter 中的击键?【英文标题】:How to bind async method to a keystroke in Tkinter? 【发布时间】:2018-05-17 14:18:18 【问题描述】:考虑以下示例:
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))
在 tkinter 中将异步方法绑定到击键的正确方法是什么? 我尝试过类似的方法:
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))
...和一堆其他的组合,但无济于事。
【问题讨论】:
【参考方案1】:tkinter
本身是异步的,这要归功于事件循环、after
方法和bindings。
但是,如果您尝试坚持使用 asyncio
也是可能的,但首先让我们考虑一下您尝试了什么。
您的第一次尝试显然是失败的,因为您尝试将spam
作为通用函数调用,而它是coroutine
。您的其他尝试比第一次更正确,但 await coroutine
或 yield from coroutine
只能用于从另一个协程启动协程,因此再次失败。
因此,启动该野兽的正确方法是对其执行的调度,使用不言自明的方法ensure_future
(或旧的async
,这只是一个已弃用的别名)。 p>
试试这个例子:
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))
另外,我认为值得一提的是this 问题,因为您使用的是update
方法。
【讨论】:
Cyn 你解释一下为什么你使用update()
而不是update_idletasks()
?见Tkinter-Docs
@buhtz,这条线直接来自问题。我还在回答中提到了该“问题”的主题。实际上,在这个问题的背景下,没有区别。以上是关于如何将异步方法绑定到 Tkinter 中的击键?的主要内容,如果未能解决你的问题,请参考以下文章
如何让 python 检测键盘的击键并根据 Windows 中的输入键发送不同的字符串