如何将异步方法绑定到Tkinter中的击键?

时间:2017-12-04 06:47:11

标签: python tkinter python-3.5 python-3.6 python-asyncio

考虑以下示例:

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 个答案:

答案 0 :(得分:3)

由于事件循环,after方法和bindings

tkinter本身是异步的。

但是,如果您仍然坚持使用asyncio,那么首先考虑一下您的尝试。

您的第一次尝试显然是失败,因为当spamcoroutine时,您尝试将await coroutine作为通用函数进行调用。您的其他尝试比第一次尝试更正确,但yield from coroutineimport 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)) 只能用于从另一个协程启动协程,因此它会再次失败。

因此,启动该野兽的正确方法是使用自解释方法ensure_future(或旧的async 对其执行进行调度,这只是一个不赞成使用的别名)。

试试这个例子:

update

此外,我认为值得提及this问题,因为您使用了 try (Socket socket=new Socket(ipAddress, port); ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream())) { //this is how you can use socket & out out.write(null); socket.getInetAddress(); } 方法。