Ravi238
Ravi238

Reputation: 21

Tkinter indeterminate progress bar getting stuck with threading

I am facing issue with the progress bar. In the go_ahead function() I am actually calling another python program which processes two files for fuzzy matching. For this, I have just replaced it with a sleep(5) to show minimal code. The progress bar gets stuck and when the program completes, it starts scrolling. It also remains freezed when the program starts. Can someone please help resolving this issue of progress bar?

from tkinter import filedialog
from tkinter import ttk
import time as T
import datetime
import tkinter.messagebox as tkMessageBox
from os import system
import os
import threading

import sys
if sys.version_info[0] < 3:
   import Tkinter as Tk
else:
   import tkinter as Tk
fname1=[]
fname2=[]


root = Tk.Tk()
root.wm_title("Fuzzy Match Wizard")
root.resizable(False, False)
window_height = 600
window_width = 1000
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
x_cordinate = int((screen_width/2) - (window_width/2))
y_cordinate = int((screen_height/2) - (window_height/2))
root.geometry("{}x{}+{}+{}".format(window_width, window_height, x_cordinate, y_cordinate))
#root.configure(background='PaleGreen4')
root.configure(borderwidth=6)
root.configure(relief='ridge')
root.configure(highlightcolor="black")
root.configure(takefocus="15")
root.configure(width="5")





def go_ahead():
    root.update()
    T.sleep(10)
    root.update()
    tkMessageBox.showinfo(title="Greetings", message="Fuzzy Match Completed")

def run_progressbar():
    global p
    global p_Lab

    p = ttk.Progressbar(root,orient="horizontal",length=200,mode="indeterminate",takefocus=True,maximum=100)
    p.place(relx=0.43, rely=0.65, height=15, width=160)      
    p_Lab = Tk.Label(root,text='Processing..Hold On..')
    p_Lab.place(relx=0.43, rely=0.68, height=50, width=160)
    p.start()
    p.update_idletasks()


def start_submit_thread():
    global submit_thread
    run_progressbar()
    submit_thread = threading.Thread(target=go_ahead())
    submit_thread.daemon = True
    submit_thread.start()
    root.after(20, check_submit_thread)

def check_submit_thread():
    if submit_thread.is_alive():
        p.update_idletasks()
        root.after(20, check_submit_thread)
    else:
        p.update_idletasks()
        p.stop()
        p.destroy()
        p_Lab.destroy()
        root.update()


def justprint(root):
    start_time = datetime.datetime.now().time().strftime('%H:%M:%S')
    print ("Start", start_time)
    start_submit_thread()




OkButton = Tk.Button(root, text = 'Perform Matches', height=5,width = 15,borderwidth=3,bg='grey',fg='black', command=lambda root=root:justprint(root))
OkButton.place(relx=0.45, rely=0.77, height=50, width=100)
OkButton2 = Tk.Label(root, text="(Once you start, it cannot be reverted back. Wait until processing is completed)")
OkButton2.place(relx=0.3, rely=0.88, height=20, width=460)

def main():
    Tk.mainloop()
if __name__ == '__main__':
    main()

Upvotes: 0

Views: 766

Answers (1)

martineau
martineau

Reputation: 123463

Your code isn't working for two primary reason, the first being because it's accessing tkinter from a thread and tkinter doesn't support multi-threading. That can be fixed by removing everything in the go_ahead() function except for the sleep() call, and instead do the things removed in the check_submit_thread() function—if necessary—which is repeatedly checking the status of the worker thread from the main one.

The other significant mistake I noticed was that the thread object was being created using:

threading.Thread(target=go_ahead())

rather than:

threading.Thread(target=go_ahead)

The problem with the former is that it calls go_ahead() as the thread object is being created rather than when the thread object's start() method is called.

In addition I made other relatively minor changes so the code adheres better to the PEP 8 - Style Guide for Python Code recommendations to improved its readability, plus actually be runnable using either Python 2 or 3.

from __future__ import print_function
import datetime
import sys
import threading
import time as T
try:
    import Tkinter as tk
    import tkFileDialog
    import tkMessageBox
    import ttk
except ModuleNotFoundError:  # Python 3
    import tkinter as tk
    from tkinter import filedialog as tkFileDialog
    import tkinter.messagebox as tkMessageBox
    from tkinter import ttk

fname1=[]
fname2=[]

root = tk.Tk()
root.wm_title("Fuzzy Match Wizard")
root.resizable(False, False)
window_height = 600
window_width = 1000
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
x_cordinate = int((screen_width/2) - (window_width/2))
y_cordinate = int((screen_height/2) - (window_height/2))
root.geometry("{}x{}+{}+{}".format(window_width, window_height, x_cordinate, y_cordinate))
root.configure(
#    background='PaleGreen4',
    relief='ridge', highlightcolor="black", takefocus="15", width="5")

def go_ahead():
    """ This represents the fuzzy matching thread. """
    # DON'T USE/ACCESS TKINTER IN THIS THREAD!
    T.sleep(10)

def run_progressbar():
    global p
    global p_Lab

    p = ttk.Progressbar(root, orient="horizontal", length=200, mode="indeterminate",
                        takefocus=True, maximum=100)
    p.place(relx=0.43, rely=0.65, height=15, width=160)
    p_Lab = tk.Label(root,text='Processing..Hold On..')
    p_Lab.place(relx=0.43, rely=0.68, height=50, width=160)
    p.start()

def start_submit_thread():
    global submit_thread

    submit_thread = threading.Thread(target=go_ahead)
    submit_thread.daemon = True
    submit_thread.start()
    run_progressbar()
    root.after(20, check_submit_thread)

def check_submit_thread():
    if submit_thread.is_alive():
        p.step()
        root.after(20, check_submit_thread)
    else:
        p.stop()
        p.destroy()
        p_Lab.destroy()
        stop_time = datetime.datetime.now().time().strftime('%H:%M:%S')
        print("Stop", stop_time)
        tkMessageBox.showinfo(title="Greetings", message="Fuzzy Match Completed")

def justprint(root):
    start_time = datetime.datetime.now().time().strftime('%H:%M:%S')
    print("Start", start_time)
    start_submit_thread()

OkButton = tk.Button(root, text='Perform Matches', height=5, width=15, borderwidth=3,
                     bg='grey', fg='black', command=lambda root=root: justprint(root))
OkButton.place(relx=0.45, rely=0.77, height=50, width=100)
OkButton2 = tk.Label(root, text="(Once you start, it cannot be reverted back."
                                " Wait until processing is completed)")
OkButton2.place(relx=0.3, rely=0.88, height=20, width=460)

def main():
    tk.mainloop()

if __name__ == '__main__':
    main()

Upvotes: 2

Related Questions