Home > Software design >  How to make Python Tkinter GUI checks if an other thread has finished to make GUI changes?
How to make Python Tkinter GUI checks if an other thread has finished to make GUI changes?

Time:05-06

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.

CodePudding user response:

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
...
  • Related