MaxB
MaxB

Reputation: 458

Tkinter progressbar hangs program and doesn't continue

I have tried to implement a Tkinter progressbar using threading simply to see when a program is running, and to close the progressbar when the program ends.

import tkinter
import ttk
import time
import threading

def task(root):
    ft = ttk.Frame()
    ft.pack(expand=True, fill=tkinter.BOTH, side=tkinter.TOP)
    pb_hD = ttk.Progressbar(ft, orient='horizontal', mode='indeterminate')
    pb_hD.pack(expand=True, fill=tkinter.BOTH, side=tkinter.TOP)
    pb_hD.start(50)
    root.mainloop()


def process_of_unknown_duration(root):
    time.sleep(5)
    root.destroy()


def pBar():
    root = tkinter.Tk()
    t1=threading.Thread(target=process_of_unknown_duration, args=(root,))
    t1.start()
    task(root)  # This will block while the mainloop runs
    t1.join()


if __name__ == '__main__':
    pBar()
    #some function

My issue is that once the progressbar starts, the program just hangs and wont do anything else. Any hints?

Upvotes: 1

Views: 1476

Answers (2)

Peter Nazarenko
Peter Nazarenko

Reputation: 411

Are you still interested in this problem? Try to use the update() method for the root object instead of the threading in the simple cases. I offer the following simplified demo-solution with global variables as a start point for subsequent developments.

import tkinter
from tkinter import *
from tkinter import ttk
import time

root1 = Tk()

progrBar1 = None  # The main progress bar
win2 = None

def click_but1():
    global win2, progrBar2
    if win2 is None:
        win2 = Toplevel()  # Secondary window
        win2.title('Secondary')
        win2.protocol('WM_DELETE_WINDOW', clickClose)  # close the secondary window on [x] pressing
        but2 = Button(win2, text='Close', command=clickClose)
        but2.pack()
        but3 = Button(win2, text='Process', command=clickProcess)
        but3.pack()
        progrBar2 = ttk.Progressbar(win2, orient = 'horizontal', length = 300, mode = 'determinate')
        progrBar2.pack()
    if progrBar1:
        progrBar1.start(50)

def clickClose():
    global win2
    progrBar1.stop()
    win2.destroy()
    win2=None

def clickProcess():
    my_func()

def my_func():
    global progrBar2
    range1, range2 = 20, 40
    step1 = 100/range1
    for i in range(range1):
        for j in range(range2):
            time.sleep(0.01)
        progrBar2.step(step1)
        root1.update()  # the "update" method

root1.title('Root')  # Main window
progrBar1 = ttk.Progressbar(root1, orient = 'horizontal', mode = 'indeterminate')  # The main progress bar
but1 = Button(root1, text = 'Start', command = click_but1)
but1.pack()
progrBar1.pack()
root1.mainloop()

The progress bar in the first (main) window is moving only in the presence of the secondary window. This pogress bar stops and returns to the initial position after closing of the secondary window. The secondary window has it own progress bar for the demo purposes and to show the interaction between windows by means of the update() method.

Upvotes: 0

Olivier Samson
Olivier Samson

Reputation: 703

This is because your call root.mainloop() is blocking the execution of your code. It basically represents the loop for your UI. You might want to look at this answer for a progress bar that is launched by a button.

Upvotes: 1

Related Questions