Mathieu P.
Mathieu P.

Reputation: 354

Display toplevel tk at the begining of a function

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

Answers (1)

dwb
dwb

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

  1. Run the for loop in a separate Thread (you can't run tkinter in a separate thread though)
  2. Manually update the window in your for loop

You 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

Related Questions