来自 tkinter 应用程序的多线程
multithreading from a tkinter app
我有一个在主线程上运行的 tkinter 应用程序。在收到用户的一些输入后,将创建一个新线程以在单独的 class 中执行功能。主线程继续 Toplevel 进度 window。
我的问题是,当第二个线程完成其任务时,如何与主线程通信以关闭进度window?
import tkinter as tk
from tkinter import ttk
from threading import Thread
import time
class Application:
def __init__(self, master):
# set main window
frame = tk.Frame(master, width=300, height=100)
frame.pack(fill=tk.BOTH)
# button widget
run_button = tk.Button(frame, text="GO", command=self.do_something)
run_button.pack()
# simulate some gui input from user
self.user_input = "specified by user"
def do_something(self):
thread1 = Thread(target=FunctionClass, args=(self.user_input,))
thread1.start() # launch thread
ProgressWindow() # main thread continues to new tkinter window
class ProgressWindow(tk.Toplevel):
""" displays progress """
def __init__(self):
super().__init__()
self.progress = ttk.Progressbar(
self, orient="horizontal", length=300, mode="indeterminate")
self.progress.pack()
self.note = "Processing data..."
self.p_label = tk.Label(self, text=self.note)
self.p_label.pack()
self.progress.start(50)
class FunctionClass:
""" thread1 works on this class """
def __init__(self, user_data):
self.user_data = user_data
self.do_something_else()
def do_something_else(self):
# simulate thread 1 working
time.sleep(3)
print("Thread1 job done")
if __name__ == "__main__":
root = tk.Tk()
Application(root)
root.mainloop()
* 更新 *
tkinter 的 event_generate
按照 iCart 的建议运行良好。请参阅下面的代码更新。
import tkinter as tk
from tkinter import ttk, messagebox
from threading import Thread
import time
class Application:
def __init__(self, master):
# set main window
frame = tk.Frame(master, width=300, height=100)
frame.pack(fill=tk.BOTH)
# button widget
run_button = tk.Button(frame, text="GO", command=self.do_something)
run_button.pack()
# simulate some gui input from user
self.user_input = "specified by user"
def do_something(self):
thread1 = Thread(target=FunctionClass, args=(self.user_input,))
thread1.start() # launch thread
ProgressWindow() # main thread continues to new tkinter window
class ProgressWindow(tk.Toplevel):
""" displays progress """
def __init__(self):
super().__init__()
self.progress = ttk.Progressbar(self, orient="horizontal", length=300, mode="indeterminate")
self.progress.pack()
self.note = "Processing data..."
self.p_label = tk.Label(self, text=self.note)
self.p_label.pack()
self.progress.start(50)
class FunctionClass:
""" thread1 works on this class """
def __init__(self, user_data):
self.user_data = user_data
self.do_something_else()
def do_something_else(self):
# simulate thread 1 working
time.sleep(3)
print("Thread1 job done")
# call <<stop>> virtual event (unsure if 'tail' is necessary here)
root.event_generate("<<stop>>", when="tail")
def end_program(*args):
""" called with tkinter event_generate command after thread completion """
messagebox.showinfo("Complete", "Processing Complete")
root.destroy()
if __name__ == "__main__":
root = tk.Tk()
Application(root)
root.bind("<<stop>>", end_program) # bind to event
root.mainloop()
我对 tkinter 不太熟悉,所以我不能给你看代码,但你应该看看 tkinter 的事件系统,特别是触发自定义事件。
This question 可能会帮助您入门
您可以使用 Queue
,来自 Queue
模块。
def get_queue(self, queue):
status = queue.get()
if status:
self.do_your_action()
self.master.after(1000, self.get_queue)
并且在进度条中window,你传递队列并在进度条完成时将一些东西放入其中。
我有一个在主线程上运行的 tkinter 应用程序。在收到用户的一些输入后,将创建一个新线程以在单独的 class 中执行功能。主线程继续 Toplevel 进度 window。
我的问题是,当第二个线程完成其任务时,如何与主线程通信以关闭进度window?
import tkinter as tk
from tkinter import ttk
from threading import Thread
import time
class Application:
def __init__(self, master):
# set main window
frame = tk.Frame(master, width=300, height=100)
frame.pack(fill=tk.BOTH)
# button widget
run_button = tk.Button(frame, text="GO", command=self.do_something)
run_button.pack()
# simulate some gui input from user
self.user_input = "specified by user"
def do_something(self):
thread1 = Thread(target=FunctionClass, args=(self.user_input,))
thread1.start() # launch thread
ProgressWindow() # main thread continues to new tkinter window
class ProgressWindow(tk.Toplevel):
""" displays progress """
def __init__(self):
super().__init__()
self.progress = ttk.Progressbar(
self, orient="horizontal", length=300, mode="indeterminate")
self.progress.pack()
self.note = "Processing data..."
self.p_label = tk.Label(self, text=self.note)
self.p_label.pack()
self.progress.start(50)
class FunctionClass:
""" thread1 works on this class """
def __init__(self, user_data):
self.user_data = user_data
self.do_something_else()
def do_something_else(self):
# simulate thread 1 working
time.sleep(3)
print("Thread1 job done")
if __name__ == "__main__":
root = tk.Tk()
Application(root)
root.mainloop()
* 更新 *
tkinter 的 event_generate
按照 iCart 的建议运行良好。请参阅下面的代码更新。
import tkinter as tk
from tkinter import ttk, messagebox
from threading import Thread
import time
class Application:
def __init__(self, master):
# set main window
frame = tk.Frame(master, width=300, height=100)
frame.pack(fill=tk.BOTH)
# button widget
run_button = tk.Button(frame, text="GO", command=self.do_something)
run_button.pack()
# simulate some gui input from user
self.user_input = "specified by user"
def do_something(self):
thread1 = Thread(target=FunctionClass, args=(self.user_input,))
thread1.start() # launch thread
ProgressWindow() # main thread continues to new tkinter window
class ProgressWindow(tk.Toplevel):
""" displays progress """
def __init__(self):
super().__init__()
self.progress = ttk.Progressbar(self, orient="horizontal", length=300, mode="indeterminate")
self.progress.pack()
self.note = "Processing data..."
self.p_label = tk.Label(self, text=self.note)
self.p_label.pack()
self.progress.start(50)
class FunctionClass:
""" thread1 works on this class """
def __init__(self, user_data):
self.user_data = user_data
self.do_something_else()
def do_something_else(self):
# simulate thread 1 working
time.sleep(3)
print("Thread1 job done")
# call <<stop>> virtual event (unsure if 'tail' is necessary here)
root.event_generate("<<stop>>", when="tail")
def end_program(*args):
""" called with tkinter event_generate command after thread completion """
messagebox.showinfo("Complete", "Processing Complete")
root.destroy()
if __name__ == "__main__":
root = tk.Tk()
Application(root)
root.bind("<<stop>>", end_program) # bind to event
root.mainloop()
我对 tkinter 不太熟悉,所以我不能给你看代码,但你应该看看 tkinter 的事件系统,特别是触发自定义事件。
This question 可能会帮助您入门
您可以使用 Queue
,来自 Queue
模块。
def get_queue(self, queue):
status = queue.get()
if status:
self.do_your_action()
self.master.after(1000, self.get_queue)
并且在进度条中window,你传递队列并在进度条完成时将一些东西放入其中。