pr0grmr
pr0grmr

Reputation: 57

How to make Python Tkinter GUI checks if an other thread has finished to make GUI changes?

I am trying multi-threading in Tkinter. I have a button which allows a user to pick an .xlsx file using a filepicker, which is then sent to a database. The database responds with a dataframe object which is then shown to the user via a treeview.

I have a function File_Dialog(treeview), which is used for this purpose. When i get the filepath, I send the filepath to the database using a different thread.

class databaseGetDF(Thread):
    def __init__(self,filepath):
        super().__init__()  
        self.filepath = filepath
        self.df = None

    def run(self):
        self.df = db.addCollectionData(self.filepath,True)

In my File_Dialog(treeview), i do this,

download_thread = databaseGetDF(filename)
download_thread.start()
# I want to check now if my thread has finished
while download_thread.is_alive:
     print("thread alive")
df = download_thread.df

and then, I display the DF using treeview. The problem is that the while loop causes my GUI to become unresponsive until the thread finishes. If I do not use a while loop, the database does gets updated in a separate loop but the GUI doesn't since it does not wait for the thread to return a dataframe.

Regarding my frames structure, I am using a notebook tkinter structure. I have a button which opens the file dialog box.

def configureHomeFrame(frame):
   
    importButton = Button(frame, text='IMPORT DATASET (XLSX)', command=lambda:  File_dialog(treeView), height=5,
                          width=35,
                          bg='#bdbdbd')

The frame attribute is a notebook frame.

Thanks.

Upvotes: 1

Views: 465

Answers (1)

acw1668
acw1668

Reputation: 46669

You can use .wait_variable() function to replace the while loop because .wait_variable() does not block tkinter mainloop():

  • create a tkinter variable: var1 = StringVar()
  • pass this variable to databaseGetDF class
  • call .wait_variable(var1) instead of the while loop
  • update this variable when the thread task completes

Example:

class databaseGetDF(Thread):
    def __init__(self, filepath, notify_var):
        super().__init__()  
        self.filepath = filepath
        self.notify_var = notify_var
        self.df = None

    def run(self):
        self.df = db.addCollectionData(self.filepath, True)
        # update self.notify_var
        self.notify_var.set('')

...
# create a tkinter variable
var1 = StringVar()
# pass the variable to databaseGetDF class
download_thread = databaseGetDF(filename, var1)
download_thread.start()
# wait for the thread completes
root.wait_variable(var1) # assume root is the root window
# thread completed, so you can get the dataframe
df = download_thread.df
...

Upvotes: 1

Related Questions