一起使用asyncio和Tkinter(或另一个GUI库),而无需冻结GUI

我想asynciotkinterGUI结合使用。我是新手asyncio,对它的理解不是很详细。单击第一个按钮时,此处的示例启动10个任务。任务只是用a模拟工作sleep()几秒钟。

该示例代码在Python上运行良好3.6.4rc1

是GUI被冻结。当我按下第一个按钮并启动10个异步任务时,除非完成所有任务,否则无法在GUI中按下第二个按钮。GUI永远不会冻结-这是我的目标。

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

from tkinter import *

from tkinter import messagebox

import asyncio

import random

def do_freezed():

""" Button-Event-Handler to see if a button on GUI works. """

messagebox.showinfo(message='Tkinter is reacting.')

def do_tasks():

""" Button-Event-Handler starting the asyncio part. """

loop = asyncio.get_event_loop()

try:

loop.run_until_complete(do_urls())

finally:

loop.close()

async def one_url(url):

""" One task. """

sec = random.randint(1, 15)

await asyncio.sleep(sec)

return 'url: {}\tsec: {}'.format(url, sec)

async def do_urls():

""" Creating and starting 10 tasks. """

tasks = [

one_url(url)

for url in range(10)

]

completed, pending = await asyncio.wait(tasks)

results = [task.result() for task in completed]

print('\n'.join(results))

if __name__ == '__main__':

root = Tk()

buttonT = Button(master=root, text='Asyncio Tasks', command=do_tasks)

buttonT.pack()

buttonX = Button(master=root, text='Freezed???', command=do_freezed)

buttonX.pack()

root.mainloop()

回答:

…是因为这个错误,我无法再次运行任务。

Exception in Tkinter callback

Traceback (most recent call last):

File "/usr/lib/python3.6/tkinter/__init__.py", line 1699, in __call__

return self.func(*args)

File "./tk_simple.py", line 17, in do_tasks

loop.run_until_complete(do_urls())

File "/usr/lib/python3.6/asyncio/base_events.py", line 443, in run_until_complete

self._check_closed()

File "/usr/lib/python3.6/asyncio/base_events.py", line 357, in _check_closed

raise RuntimeError('Event loop is closed')

RuntimeError: Event loop is closed

回答:

谁可以成为多线程解决方案?只有两个线程-每个循环都有自己的线程?

:审查此问题和答案后,它几乎与所有GUI库有关(例如PygObject / Gtk,wxWidgets,Qt等)。

回答:

在对您的代码进行稍作修改后,我event_loop在主线程中创建了asyncio并将其作为参数传递给asyncio线程。现在,在提取网址时,Tkinter不会冻结。

from tkinter import *

from tkinter import messagebox

import asyncio

import threading

import random

def _asyncio_thread(async_loop):

async_loop.run_until_complete(do_urls())

def do_tasks(async_loop):

""" Button-Event-Handler starting the asyncio part. """

threading.Thread(target=_asyncio_thread, args=(async_loop,)).start()

async def one_url(url):

""" One task. """

sec = random.randint(1, 8)

await asyncio.sleep(sec)

return 'url: {}\tsec: {}'.format(url, sec)

async def do_urls():

""" Creating and starting 10 tasks. """

tasks = [one_url(url) for url in range(10)]

completed, pending = await asyncio.wait(tasks)

results = [task.result() for task in completed]

print('\n'.join(results))

def do_freezed():

messagebox.showinfo(message='Tkinter is reacting.')

def main(async_loop):

root = Tk()

Button(master=root, text='Asyncio Tasks', command= lambda:do_tasks(async_loop)).pack()

buttonX = Button(master=root, text='Freezed???', command=do_freezed).pack()

root.mainloop()

if __name__ == '__main__':

async_loop = asyncio.get_event_loop()

main(async_loop)

以上是 一起使用asyncio和Tkinter(或另一个GUI库),而无需冻结GUI 的全部内容, 来源链接: utcz.com/qa/402990.html

回到顶部