1

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?

MaxB
  • 428
  • 1
  • 8
  • 24
  • 1
    `tkinter` doesn't support multi-threading. You can use threads, but they cannot interact with the GUI. One of the workarounds is to periodically have `mainloop()` call a function via the universal [`after()`](http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/universal.html) widget function. The called function _can_ access `tkinter` functions & widgets. – martineau Mar 28 '19 at 18:09
  • I ran your code and it works. One thing I had to change though was the 'import ttk' line. I just changed it to 'from tkinter import ttk' – RockAndRoleCoder Mar 28 '19 at 18:45
  • @RockAndRoleCoder hmm I tried that and it didn't seem to work – MaxB Mar 28 '19 at 18:58
  • Maybe try moving your root.destroy to outside your thread, and tell it to wait 6 sec instead of 5 (to allow the thread some time). I'm curious if asking the thread to destroy the main thread is causing your issue. – RockAndRoleCoder Mar 29 '19 at 02:30

2 Answers2

1

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.

Olivier Samson
  • 609
  • 4
  • 13
  • I made a go at it using the solution you linked and while the program runs and completes, the status bar itself doesn't move and ends up freezing. – MaxB Mar 28 '19 at 19:13
0

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.

Peter Nazarenko
  • 411
  • 1
  • 7
  • 16