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