Reputation: 479
hello people I have a problem, with a progress bar in tkinter, you will see:
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()
Upvotes: 1
Views: 3638
Reputation: 142651
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.
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.
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.
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()
Upvotes: 2