0

Why is the progressbar starting after the print-commands?

I want to start the progressbar first. And wenn the 2nd print command ("After the sleep statement") was excecuted, I want to stop the progressbar. Any ideas?

from tkinter import Tk 
from tkinter.ttk import Progressbar 
import time

# root window 
root = Tk() 
root.geometry('300x120') 
root.title('Progressbar Demo')

root.grid()

# progressbar 
pb = Progressbar(
    root,
    orient='horizontal',
    mode='indeterminate',
    length=280 )

# place the progressbar 
pb.grid(column=0, row=0, columnspan=2, padx=10, pady=20)

pb.start()



print("Before the sleep statement")
time.sleep(5)
print("After the sleep statement")

# pb.stop()

root.mainloop()

The current problem is that the progressbar is only started after time.sleep command.

Adler Müller
  • 248
  • 1
  • 14

2 Answers2

3

@Kaz's answer without the need for the button:

import threading
import time

from tkinter import Tk, Button
from tkinter.ttk import Progressbar


# root window
root = Tk()
root.geometry('300x120')
root.title('Progressbar Demo')

# progressbar
pb = Progressbar(root, orient="horizontal", length=280)
pb.grid(column=0, row=0, columnspan=2, padx=10, pady=20)

def statement():
    global stop_the_progressbar
    print("Before the sleep statement")
    time.sleep(5)
    print("After the sleep statement")
    stop_the_progressbar = True

def tkinter_loop():
    if stop_the_progressbar:
        pb.stop()
    else:
        root.after(100, tkinter_loop)

# Start the progressbar
pb.start()
threading.Thread(target=statement, daemon=True).start()
stop_the_progressbar = False
tkinter_loop()

root.mainloop()

It uses a .after loop to check if the progressbar should be stopped. Look at this for more details on how .after works. Also please note that you shouldn't call any tkinter methods from the new thread.

This example doesn't run well on IDLE because of a bug in IDLE. The text "Before the sleep statement" will be printed after the thread stops but it actually runs at the correct time.

TheLizzard
  • 7,248
  • 2
  • 11
  • 31
  • Okay thanks for your solution. When I click a 2nd time on button in "Kaz" solution, the following RuntimeError is showing: "threads can only be started once". can that be bypassed somehow? – Adler Müller Sep 07 '21 at 10:21
  • @AdlerMüller I just edited that answer to solve that problem :D – TheLizzard Sep 07 '21 at 10:22
2

The progress bar and all graphical elements of tkinter are launched from main loop (root.mainloop()). So, sleeping is done before the main loop. If you want so, you should implement spleeping IN main loop.

Furthermore, for a non-instantaneous processing, it's recommended to use a separate thread (e.g. with threading.Tread) to avoid blocking the GUI thread.

You can do something like this :

import threading
import time

from tkinter import Tk, Button
from tkinter.ttk import Progressbar


# root window
root = Tk()
root.geometry('300x120')
root.title('Progressbar Demo')

root.grid()

# progressbar
pb = Progressbar(root, orient='horizontal', mode='indeterminate', length=280)
# place the progressbar
pb.grid(column=0, row=0, columnspan=2, padx=10, pady=20)

def statement():
    pb.start()
    print("Before the sleep statement")
    time.sleep(5)
    print("After the sleep statement")
    pb.stop()

button = Button(root, text="Start", command=lambda: threading.Thread(target=statement).start())
button.grid(column=0, row=1)

root.mainloop()

TheLizzard
  • 7,248
  • 2
  • 11
  • 31
Kaz
  • 1,047
  • 8
  • 18
  • Okay thanks. Is it also possible without a button? So it starts automatically? – Adler Müller Sep 07 '21 at 09:42
  • It isn't a good idea to use call `tkinter` methods from other threads. It can crash the python interpreter without giving you a traceback. – TheLizzard Sep 07 '21 at 09:51
  • @TheLizzard I'm ok with you (here pb.start and pb.stop), but it's here a small demonstrator. Better code is to make a complet GUI. – Kaz Sep 07 '21 at 10:00
  • I am saying that you shouldn't use any methods on any `tkinter` widgets from your `statement` function. – TheLizzard Sep 07 '21 at 10:02
  • When I click a 2nd time on button, the following RuntimeError is showing: "threads can only be started once". can that be bypassed somehow? – Adler Müller Sep 07 '21 at 10:20
  • 1
    @AdlerMüller Fixed the code in this answer so that you aren't going to get that error, if you press the button twice. – TheLizzard Sep 07 '21 at 10:22
  • Wow, this answer was fast and accurate. Thank you very much! – Adler Müller Sep 07 '21 at 10:23