如何在 Tkinter 中实现不确定的进度条?
How to implement indeterminate Progressbar in Tkinter?
我的应用程序偶尔会有一些耗时的后台进程 运行。我想使用简单的 indeterminate ttk.Progressbar
来证明该应用程序正在运行。
但是,我的实现只显示静态进度条。
无论如何,这是我实现它的方式。
class MyApp(ttk.Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master)
fname = 'test.txt'
self.build_ui()
self.process_file(fname)
def process_file(self, fname):
self.show_progress(True)
fdata = self.read_file(fname)
fdata = self.spellcheck(fdata)
self.show_progress(False)
return fdata
def show_progress(self, start)
if start:
self.prog_win = tk.Toplevel()
self.prog_win.title('Working...')
self.prog_win.resizable(0, 0)
self.progress_bar = ttk.Progressbar(self.prog_win,
orient=tk.HORIZONTAL,
mode='indeterminate',
takefocus=True)
self.progress_bar.grid()
self.progress_bar.start()
else:
self.progress_bar.stop()
self.prog_win.destroy()
root = tk.Tk()
root.update()
gui = MyApp(root)
gui.mainloop()
上面的代码没有按预期工作。 Progressbar
看起来是静止的,它不会移动,永远挂在那里。我尝试使用线程,但如果我在单独的 Thread
中启动 show_progress
,它总是在处理完成后执行。
我做错了什么?
问题是 self.read_file()
和 self.spellcheck()
正在阻塞,这会阻止 Tkinter 在其主循环中更新进度条。解决这个问题的一个简单方法是在单独的线程中进行处理,并定期检查线程是否完成了它的工作。
import threading
class MyApp(ttk.Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master)
fname = 'test.txt'
self.build_ui()
self.process_file(fname)
def process_file(self, fname):
self.show_progress(True)
# Start thread to process file.
self.thread = threading.Thread(target=self.process_file_worker, args=(fname,))
self.thread.daemon = True # Allow the program to terminate without waiting for the thread to finish.
self.thread.start()
# Start checking the thread.
self.process_file_check()
def process_file_check(self):
if self.thread.is_alive():
# Thread is still running, check thread again in 10 milliseconds.
self.after(10, self.process_file_check)
else:
# Thread finished, handle processed results.
# Do something with `self.fdata`.
self.show_progress(False)
def process_file_worker(self, fname):
# This is run inside the thread.
fdata = self.read_file(fname)
fdata = self.spellcheck(fdata)
self.fdata = fdata
def show_progress(self, start):
if start:
self.prog_win = tk.Toplevel()
self.prog_win.title('Working...')
self.prog_win.resizable(0, 0)
self.progress_bar = ttk.Progressbar(self.prog_win,
orient=tk.HORIZONTAL,
mode='indeterminate',
takefocus=True)
self.progress_bar.grid()
self.progress_bar.start()
else:
self.progress_bar.stop()
self.prog_win.destroy()
root = tk.Tk()
root.update()
gui = MyApp(root)
gui.mainloop()
我的应用程序偶尔会有一些耗时的后台进程 运行。我想使用简单的 indeterminate ttk.Progressbar
来证明该应用程序正在运行。
但是,我的实现只显示静态进度条。
无论如何,这是我实现它的方式。
class MyApp(ttk.Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master)
fname = 'test.txt'
self.build_ui()
self.process_file(fname)
def process_file(self, fname):
self.show_progress(True)
fdata = self.read_file(fname)
fdata = self.spellcheck(fdata)
self.show_progress(False)
return fdata
def show_progress(self, start)
if start:
self.prog_win = tk.Toplevel()
self.prog_win.title('Working...')
self.prog_win.resizable(0, 0)
self.progress_bar = ttk.Progressbar(self.prog_win,
orient=tk.HORIZONTAL,
mode='indeterminate',
takefocus=True)
self.progress_bar.grid()
self.progress_bar.start()
else:
self.progress_bar.stop()
self.prog_win.destroy()
root = tk.Tk()
root.update()
gui = MyApp(root)
gui.mainloop()
上面的代码没有按预期工作。 Progressbar
看起来是静止的,它不会移动,永远挂在那里。我尝试使用线程,但如果我在单独的 Thread
中启动 show_progress
,它总是在处理完成后执行。
我做错了什么?
问题是 self.read_file()
和 self.spellcheck()
正在阻塞,这会阻止 Tkinter 在其主循环中更新进度条。解决这个问题的一个简单方法是在单独的线程中进行处理,并定期检查线程是否完成了它的工作。
import threading
class MyApp(ttk.Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master)
fname = 'test.txt'
self.build_ui()
self.process_file(fname)
def process_file(self, fname):
self.show_progress(True)
# Start thread to process file.
self.thread = threading.Thread(target=self.process_file_worker, args=(fname,))
self.thread.daemon = True # Allow the program to terminate without waiting for the thread to finish.
self.thread.start()
# Start checking the thread.
self.process_file_check()
def process_file_check(self):
if self.thread.is_alive():
# Thread is still running, check thread again in 10 milliseconds.
self.after(10, self.process_file_check)
else:
# Thread finished, handle processed results.
# Do something with `self.fdata`.
self.show_progress(False)
def process_file_worker(self, fname):
# This is run inside the thread.
fdata = self.read_file(fname)
fdata = self.spellcheck(fdata)
self.fdata = fdata
def show_progress(self, start):
if start:
self.prog_win = tk.Toplevel()
self.prog_win.title('Working...')
self.prog_win.resizable(0, 0)
self.progress_bar = ttk.Progressbar(self.prog_win,
orient=tk.HORIZONTAL,
mode='indeterminate',
takefocus=True)
self.progress_bar.grid()
self.progress_bar.start()
else:
self.progress_bar.stop()
self.prog_win.destroy()
root = tk.Tk()
root.update()
gui = MyApp(root)
gui.mainloop()