如何在Tkinter中实现不确定的Progressbar?

时间:2016-02-03 23:40:12

标签: python tkinter tk

我的应用程序偶尔会运行一些耗时的后台进程。我想表明应用程序正在使用简单的不确定 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显示为静态,它不会移动,只会永远挂在那里。我尝试使用线程但是如果我在单独的show_progress中启动Thread,它总是在处理完成后执行。

我做错了什么?

1 个答案:

答案 0 :(得分:2)

问题是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()