简体   繁体   English

用线程在 tkinter 中进度条

[英]bar progress in tkinter with thread

hello people I have a problem, with a progress bar in tkinter, you will see:大家好,我有一个问题,在 tkinter 中有一个进度条,你会看到:

I execute a method and I want that while this action is being performed, a progress bar appears, the problem is that the bar does not stop when the method ends, I don't know how to do that ... some help please我执行了一个方法,我希望在执行此操作时,会出现一个进度条,问题是方法结束时进度条不会停止,我不知道该怎么做...请帮忙

import threading
import tkinter as tk
import tkinter.ttk as ttk


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Progressbar example")
        self.button = tk.Button(self, text="Start", command=self.start_action)
        self.button.pack(padx=10, pady=10)

    def start_action(self):
        self.button.config(state=tk.DISABLED)
        t = threading.Thread(target=self.contar)
        windows_bar = WinProgressBar(self)
        self.after(t.start())

    def contar(self):
        for i in range(1000000):
            print("está contando", i)
        return True


class WinProgressBar(tk.Toplevel):
    def __init__(self, parent):
        super().__init__(parent)
        self.title("Barr progress")
        self.geometry("300x200")
        self.progressbar = ttk.Progressbar(self, mode="indeterminate")
        self.progressbar.place(x=30, y=60, width=200)
        self.progressbar.start(20)


if __name__ == "__main__":
    app = App()
    app.mainloop()

You can try to stop it in threat你可以试着阻止它的威胁

def contar(self):
    for i in range(500):
        print("está contando", i)
    
    self.windows_bar.progressbar.stop()
    self.windows_bar.destroy()
    self.button.config(state=tk.NORMAL)

import threading
import tkinter as tk
import tkinter.ttk as ttk


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Progressbar example")
        self.button = tk.Button(self, text="Start", command=self.start_action)
        self.button.pack(padx=10, pady=10)

    def start_action(self):
        self.button.config(state=tk.DISABLED)
        
        t = threading.Thread(target=self.contar)
        t.start()

        self.windows_bar = WinProgressBar(self)
        
    def contar(self):
        for i in range(500):
            print("está contando", i)

        print('stop')            
        self.windows_bar.progressbar.stop()
        self.windows_bar.destroy()
        self.button.config(state=tk.NORMAL)
        
        
class WinProgressBar(tk.Toplevel):
    def __init__(self, parent):
        super().__init__(parent)
        self.title("Barr progress")
        self.geometry("300x200")
        self.progressbar = ttk.Progressbar(self, mode="indeterminate")
        self.progressbar.place(x=30, y=60, width=200)
        self.progressbar.start(20)


if __name__ == "__main__":
    app = App()
    app.mainloop()

Many GUI frameworks don't like to change widgets in thread and then you can use variable self.running (which will be shared between both threads) to inform program if thread is running.许多 GUI 框架不喜欢更改线程中的小部件,然后您可以使用变量self.running (将在两个线程之间共享)来通知程序线程是否正在运行。

def contar(self):
    self.running = True

    for i in range(500):
        print("está contando", i)

    self.running = False

and in main thread you can use after() to periodically check this variable to stop progressbar and/or close window - and this time main thread is changing widgets.在主线程中,您可以使用after()定期检查此变量以停止进度条和/或关闭窗口 - 这次主线程正在更改小部件。

def check_thread(self):
    if self.running:
        self.after(1000, self.check_thread) # run again after 1s (1000ms)
    else:
        print('stop')
        self.windows_bar.progressbar.stop()
        self.windows_bar.destroy()
        self.button.config(state=tk.NORMAL)

import threading
import tkinter as tk
import tkinter.ttk as ttk


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Progressbar example")
        self.button = tk.Button(self, text="Start", command=self.start_action)
        self.button.pack(padx=10, pady=10)

    def start_action(self):
        self.button.config(state=tk.DISABLED)
        
        t = threading.Thread(target=self.contar)
        t.start()

        self.windows_bar = WinProgressBar(self)

        self.check_thread() # run first time
        
    def contar(self):
        self.running = True
        for i in range(500):
            print("está contando", i)
        self.running = False

    def check_thread(self):
        if self.running:
            self.after(1000, self.check_thread) # run again after 1s (1000ms)
        else:
            print('stop')
            self.windows_bar.progressbar.stop()
            self.windows_bar.destroy()
            self.button.config(state=tk.NORMAL)
        
        
class WinProgressBar(tk.Toplevel):
    def __init__(self, parent):
        super().__init__(parent)
        self.title("Barr progress")
        self.geometry("300x200")
        self.progressbar = ttk.Progressbar(self, mode="indeterminate")
        self.progressbar.place(x=30, y=60, width=200)
        self.progressbar.start(20)


if __name__ == "__main__":
    app = App()
    app.mainloop()

If threads can't share variables then you can use queue to send information from thread to main thread.如果线程不能共享变量,那么您可以使用queue将信息从线程发送到主线程。

import threading
import queue
import tkinter as tk
import tkinter.ttk as ttk


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Progressbar example")
        self.button = tk.Button(self, text="Start", command=self.start_action)
        self.button.pack(padx=10, pady=10)

    def start_action(self):
        self.button.config(state=tk.DISABLED)
        
        self.q = queue.Queue()
        t = threading.Thread(target=self.contar, args=(self.q,))
        t.start()

        self.windows_bar = WinProgressBar(self)
        
        self.check_queue()
        
    def contar(self, q):
        for i in range(200):
            print("está contando", i)
        
        q.put('finished')
        
    def check_queue(self):
        if self.q.empty() or self.q.get() != 'finished':
            self.after(1000, self.check_queue)
        else:
            print('stop')
            self.windows_bar.progressbar.stop()
            self.windows_bar.destroy()
            self.button.config(state=tk.NORMAL)
        
        
class WinProgressBar(tk.Toplevel):
    def __init__(self, parent):
        super().__init__(parent)
        self.title("Barr progress")
        self.geometry("300x200")
        self.progressbar = ttk.Progressbar(self, mode="indeterminate")
        self.progressbar.place(x=30, y=60, width=200)
        self.progressbar.start(20)


if __name__ == "__main__":
    app = App()
    app.mainloop()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM