Reputation: 354
I have an application where I want to display a progress bar during calcul. So, there is a button on my app to run a function and also display the progress bar, but the child window only appears at the end of the calcul.
To reproduce this you can try the code below :
import tkinter as tk
from tkinter import ttk as ttk
class MainApplication:
def __init__(self, master):
self.master = master
self.button_start = tk.Button(
self.master, text='Begin', command=self.upload_button)
self.button_start.place(relx=0.5, rely=0.5)
def upload_button(self):
newWindow = tk.Toplevel(self.master)
newWindow.title("Chargment...")
newWindow.geometry("400x70")
# A Label widget to show in toplevel
ttk.Label(newWindow, text="Please wait...").pack()
pb = ttk.Progressbar(newWindow, length=300)
pb.pack()
pb.start(10)
for i in range(90000):
print(i)
window = tk.Tk()
window.title("my title")
MainApplication(window)
window.mainloop()
EDIT
I have tried to use threading and after to resolve my problem but i get stuck. I don't know how to replace the after method by some calcul in python using pandas. I can't just put one value for the delay in the after method because the delay could be different if the final user work on a small table or a bigger one.
import tkinter as tk
from PIL import Image, ImageTk
import threading
import time
from tkinter import messagebox
from itertools import count
class GIFLabel(tk.Label):
"""a label that displays images, and plays them if they are gifs"""
def load(self, im):
if isinstance(im, str):
im = Image.open(im)
self.loc = 0
self.frames = []
try:
for i in count(1):
self.frames.append(ImageTk.PhotoImage(im.copy().resize((20,20))))
im.seek(i)
except EOFError:
pass
try:
self.delay = im.info['duration']
except:
self.delay = 100
if len(self.frames) == 1:
self.config(image=self.frames[0])
else:
self.next_frame()
def unload(self):
self.config(image="")
self.frames = None
def next_frame(self):
if self.frames:
self.loc += 1
self.loc %= len(self.frames)
self.config(image=self.frames[self.loc])
self.after(self.delay, self.next_frame)
class MainApplication:
def __init__(self, master):
self.master = master
self.button_start = tk.Button(self.master, text='Begin', command=self.upload_button)
self.button_start.place(relx=0.5, rely=0.5)
self.loading = GIFLabel(self.master)
self.loading.place(relx=0.5, rely=0.7)
self.loading.load('loading.gif')
def wait_generate(self):
if self.update_Thread.isAlive():
self.master.after(500, self.wait_generate)
else:
self.loading.unload()
self.loading.load('ok.png')
messagebox.showinfo("Complete", "Report generation completed!")
def upload_button(self):
self.update_Thread = threading.Thread(target=time.sleep, args=(5,))
self.update_Thread.start()
self.wait_generate()
window = tk.Tk()
window.title("my title")
MainApplication(window)
window.mainloop()
Upvotes: 0
Views: 89
Reputation: 2624
When you run through your for
loop, the tkinter window doesn't get a chance to automatically update (normally through mainloop
).
There are two options
for
loopYou can research how to use threads, but the simplest option here is to include either of the following in your for
loop:
self.master.update()
or newWindow.update()
This manually updates the window, meaning that the progress bar can be updated and become visible.
It should look like this:
for i in range(90000):
print(i)
# you can use
self.master.update()
# or
newWindow.update()
Upvotes: 1