I want to create a sort of "loading" window for a function in one of my apps. I've tried the progress bar, but I wanted to try this instead and see how it compares. The idea is to have a new window open when a button is clicked. The new window will have the word "Loading", which will then have a full stop "." appended to it after a short time delay. I've used the time.sleep()
function, but it is not quite behaving as it should.
I'll include the code below:
from tkinter import *
from tkinter.ttk import *
from tkinter import Button, Tk, HORIZONTAL
import time
def new_window():
variable_text = "Loading"
new_windy = Toplevel(main_window)
new_windy.title("New_Windy")
new_windy.geometry("200x200")
for i in range(10):
time.sleep(0.3)
new_windy.update_idletasks()
variable_text += "."
label = Label(new_windy, text=variable_text)
label.pack()
main_window = Tk()
main_window.title("AWESOME_SAUCE")
main_window.geometry('600x600')
button = Button(main_window, text="click_me", command=new_window)
button.pack()
main_window.mainloop()
The code above creates the new window at the click of the button, but instead of replacing the word "loading" each iteration with an appended full stop ".", it just creates 10 versions of the word "loading" stacked on itself with successive numbers of full stops.
There are two ways I would do this. One is using a list of words and after()
and the other would be adding dots to the end of the sentence.
Method 1: To begin with, create a list that has all the transitional words:
transition = ['Loading','Loading.','Loading..','Loading...','Loading....','Loading.....']
and now you need to index this list and call each item on the label, like:
count = 0 #a number to index the list
def new_window():
new_windy = Toplevel(main_window)
new_windy.title("New_Windy")
new_windy.geometry("200x200")
def change():
global count #globalize it
rep = main_window.after(1000,change) #repeat the function every 1 second
try: #to catch the index error
label.config(text=transition[count]) #change the text with the list index
except IndexError: #to get past the error showing up
main_window.after_cancel(rep) #stop the repetition if no more items left to show
count += 1 #increase the number by 1 over each repetition
label = Label(new_windy, text=transition[count]) #initially set the text to first element
label.pack()
change() #call the function for the first time
transition = ['Loading','Loading.','Loading..','Loading...','Loading....','Loading.....']
Method 2:
There is also another method like you did using += '.'
. That would be like:
def new_window():
global text #globalize the main text
new_windy = Toplevel(main_window)
new_windy.title("New_Windy")
new_windy.geometry("200x200")
text = 'Loading' #set the main text
def change():
global text #globalize the new text
text += '.' #add . over each iteration
rep = main_window.after(1000,change) #repeat the function every 1 second
label.config(text=text) #change the text to new text
if len(text) >= 7+5: #here 7 is the length of word 'Loading' and 5 is the maximum number of dots needed.
main_window.after_cancel(rep) #stop repeating the function
label = Label(new_windy, text=text) #set the main text at first
label.pack()
change() #call the function initially.
Now to some explanation:
but it is not quite behaving as it should.
That is because time.sleep()
messes with mainloop()
causing the unresponsiveness. Hence the GUI freezes, so instead we have to use a after()
that does not freeze the GUI. Not only time.sleep()
, also while
and for
loops mess with mainloop()
causing the GUI to be unresponsive.
it just creates 10 versions of the word "loading" stacked on itself with successive numbers of full stops.
That is because every time the code is run, a new label is created with the text "Loading", what you want to do is, create the text once, and use config()
to change the text later.
As a matter of fact your imports will cause you trouble later on, you are over writing tkinter widgets with widgets from ttk
, so change you import statement and adjust the code accordingly, like:
import tkinter as tk
from tkinter import ttk
Now if you want a tkinter widget use, tk.Label()
or if you want a ttk
widget, use ttk.Label()
and so on.