how to show a loading message in tkinter

Jerin A Mathews picture Jerin A Mathews · Jul 11, 2015 · Viewed 12.3k times · Source

I am new to tkinter. I made the required dialog box. One of my function takes some time to process. So i want to show a "loading ... " message before that function starts executing.

b1 = Button(text = "Compare",command = compare)
b1.pack()

when this button is clicked compare() function start executing. i want to show a loading message before that function starts. I tried using a label , such that i set a value to it on the starting of the compare() function. but it will only takes effect after the function finish executing.

How can i do it? please help me..

Answer

jcoppens picture jcoppens · Jul 11, 2015

Have a look at the manual for widgets. w.wait_visibility(window) waits till the widget is visible. The 'normal' way of things (in all GUI toolkits) is to put all drawing commands, such as your label, in a waiting list, and do the actual drawing when there's time, prioritizing other events). From the page:

Wait for the given widget to become visible. This is typically used to wait until a new toplevel window appears on the screen. Like wait_variable, this method enters a local event loop, so other parts of the application will still work as usual.

An example for the use of wait_visibility comes from the test_widgets.py code, where setup waits for the widget to be really shown:

class WidgetTest(unittest.TestCase):
    """Tests methods available in every ttk widget."""

    def setUp(self):
        support.root_deiconify()
        self.widget = ttk.Button(width=0, text="Text")
        self.widget.pack()
        self.widget.wait_visibility()

Of course, the compare function does have to take some appreciable time - else the label will probably disappear before it can actually be seen on the screen. Your screen is redrawn 60 times per second, so if the comparing takes less than 16 ms, you'll probably not see anything.

EDIT: A better way to do this is actually using update_idletasks. Here's some code:

import tkinter as tk
import time

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.frame = tk.Frame(self)
        self.frame.pack(side="top", fill = "both", expand=True)

        self.label = tk.Label(self, text = "Hello, world")
        button1 = tk.Button(self, text = "Start to do something",
                                  command = self.do_something)
        self.label.pack(in_=self.frame)
        button1.pack(in_=self.frame)

    def do_something(self):
        self.label.config(text = "Wait till I'm done...")
        self.label.update_idletasks()
        time.sleep(2)
        print ("end sleep")
        self.label.config(text = "I'm done doing...")

def main():
    app = SampleApp()
    app.mainloop()  
    return 0

if __name__ == '__main__':
    main()

The time.sleep in do_something simulates whatever you want to do. Click on the button to start the process.