这是一个关于使用基于tkinter的GUI执行异步任务的配方。我从引用书籍中的一份配方进行了改编。您应该能够修改它以满足您的需求。
为了保持GUI的响应性,需要
不干扰其
mainloop()
,例如通过像
join()
这样的后台线程来使GUI“挂起”,直到线程完成。这可以通过使用通用的
after()
小部件方法定期
轮询Queue
来实现。
from __future__ import print_function
try:
import Tkinter as tk, time, threading, random, Queue as queue
except ModuleNotFoundError:
import tkinter as tk, time, threading, random, queue
class GuiPart(object):
def __init__(self, master, queue, end_command):
self.queue = queue
tk.Button(master, text='Done', command=end_command).pack()
def processIncoming(self):
""" Handle all messages currently in the queue, if any. """
while self.queue.qsize():
try:
msg = self.queue.get_nowait()
print(msg)
except queue.Empty:
pass
class ThreadedClient(object):
"""
Launch the main part of the GUI and the worker thread. periodic_call()
and end_application() could reside in the GUI part, but putting them
here means that you have all the thread controls in a single place.
"""
def __init__(self, master):
"""
Start the GUI and the asynchronous threads. We are in the main
(original) thread of the application, which will later be used by
the GUI as well. We spawn a new thread for the worker (I/O).
"""
self.master = master
self.queue = queue.Queue()
self.gui = GuiPart(master, self.queue, self.end_application)
self.running = True
self.thread1 = threading.Thread(target=self.worker_thread1)
self.thread1.start()
self.periodic_call()
def periodic_call(self):
""" Check every 200 ms if there is something new in the queue. """
self.master.after(200, self.periodic_call)
self.gui.processIncoming()
if not self.running:
import sys
sys.exit(1)
def worker_thread1(self):
"""
This is where we handle the asynchronous I/O. For example, it may be
a 'select()'. One important thing to remember is that the thread has
to yield control pretty regularly, be it by select or otherwise.
"""
while self.running:
time.sleep(rand.random() * 1.5)
msg = rand.random()
self.queue.put(msg)
def end_application(self):
self.running = False
rand = random.Random()
root = tk.Tk()
client = ThreadedClient(root)
root.mainloop()
m.startConverting("test")
是阻塞的,它可能会一直占用 GUI 线程,直到join
返回。你可能需要在处理程序中启动线程。在 GUI 线程上执行长时间运行的任务会导致冻结。 - CarcigenicatestartConverting
中提交作业。这样就不需要在 GUI 线程上阻塞join
了。 - Carcigenicate