Search code examples
pythonmultithreadingtkinterprogress-barfreeze

tkinter not responding when executing command + progressbar. (multi-thread)


for my project I have implemented a graphical interface that interfaces with wearable sensors. I wrote a code (multi.py) that interfaces directly with 3 sensors. then I wrote some code for the graphical interface (GUI.py) which calls me different portions of multi.py when I click the buttons.

when I call "configure_clicked ()" and "download_clicked ()" form respective button the GUI freezes (continuing to work), because functions are called (multi.configure & multi.download ) that take some time to finish (connecting to devices and downloading data from devices). I know that I have to do another "thread"--> MULTITHREAD. please,Can anyone help me to create a multithread???

I also have "PROGRESS BAR" which should start at the start of each function but this does not happen for "configure_clicked ()" and "download_clicked ()", while I manage to slide it between "start_clicked" and "stop_clicked".

I am attaching the code. thank in advance whoever will help me.

from tkinter import * 
from tkinter import messagebox, ttk
import multi_sensor_acc_gyro1 as multi 

class GUI:

    def __init__(self,master):
        self.master=master
        self.states=[]

        ...
        ...
        #configure button
        self.btn_configure=Button(self.quadro_pulsanti_sx,relief=RAISED,command=self.configure_clicked)
        #start button
        self.btn_start=Button(self.quadro_pulsanti_dx,command=self.start_clicked,relief=RAISED)
        #stop button 
        self.btn_stop=Button(self.quadro_pulsanti_dx,command=self.stop_clicked,relief=RAISED)
        #download button
        self.btn_download=Button(self.quadro_pulsanti_dx,command=self.download_clicked,relief=RAISED)
        #save button 
        self.btn_save=Button(self.quadro_pulsanti_dx,relief=RAISED,command=self.save_clicked)
        #reset button 
        self.btn_reset=Button(self.quadro_pulsanti_sx,relief=RAISED,command=self.reset_clicked)
        #progress bar 
        self.pb=ttk.Progressbar(self.quadro_pulsanti_basso,orient=HORIZONTAL,length=350,mode="indeterminate")
        self.label_pb=Label(self.quadro_pulsanti_basso,text="")

    def configure_clicked(self):
        mac_address=["F7:64:55:AD:0A:19","F2:A1:3A:E2:F2:ED","F9:8E:32:DD:1A:EB"]
        
        output_1=multi.configure(mac_address) 
        self.states=output_1[0]
        self.loggers_acc=output_1[1]
        self.loggers_gyro=output_1[2]

        self.label_pb.configure(text="")
        messagebox.showinfo("CONFIGURE clicked","the sensors have been configured\n\nclick OK to continue")

    def start_clicked(self):

        multi.start(self.states)
        
        self.pb.start()
        self.label_pb.configure(text="registration in progress...")

    def stop_clicked(self):

        self.pb.stop()
        self.label_pb.configure(text="")

        multi.stop(self.states)
    
    def download_clicked(self):

        #self.pb.start()
        #self.label_pb.configure(text="Download in progress...")

        output_2=multi.download(self.states,self.loggers_acc,self.loggers_gyro) 
        self.df_tr_tot=output_2[0]
        self.df_gd_tot=output_2[1]
        self.df_gs_tot=output_2[2]

        #self.label_pb.configure(text="")
        #self.pb.stop()

        messagebox.showinfo("DOWNLOAD clicked","the data has been downloaded\n\nclick OK to continue")

         
    def save_clicked(self):
        
        #self.txt_pz.focus_set()
        #self.txt_pz.get()
        
        self.txt_pz.focus_set()
        id_pz=self.txt_pz.get()
        
        multi.save(self.df_tr_tot,self.df_gd_tot,self.df_gs_tot,id_pz)

        messagebox.showinfo("SAVE clicked","I dati sono stati salvati\n\ncliccare OK per continuare")

window = Tk()
window.title("   Grafic User Interface for MMR")
window.iconbitmap('C:/Users/salvo/Documents/MetaWear-SDK-Python/examples/favicon.ico')
    
height=560
width=540 
left=(window.winfo_screenwidth()-width)/2 
top=(window.winfo_screenheight()-height)/2 
geometry="%dx%d+%d+%d" % (width,height,left,top) 
window.geometry(geometry)

gui=GUI(window)

window.mainloop()

Solution

  • This is how you make sure tkinter doesn't stop responding while running a long task:

    import threading
    from time import sleep
    
    def operation():
        # Create a new thread
        new_thread = threading.Thread(target=_operation, daemon=True)
        # Start the thread
        new_thread.start()
        # continue code or run this:
        while new_thread.is_alive(): # While the new thread is still running
            # Here you can also add a loading screen
            # Make sure tkinter doesn't say that it isn't responding
            tkinter_widget.update() # `tkinter_widget` can be any tkinter widget/window
            sleep(0.1) # A bit of delay so that it doesn't use 300% of your CPU
    
    def _operation()
        # Here you can do the operation that will take a long time
        pass
    

    When you need to run the operation call operation and it will start the new thread. NOTE: make sure that you don't have any tkinter stuff in the new thread because tkinter would crash.