Tcl_AsyncDelete Error Multithreading Python

前端 未结 1 460
暖寄归人
暖寄归人 2021-01-15 08:51

I\'ve heard that threads in Python are not easy to handle and they become more tangled with tkinter.

I have the following problem. I have two classes, one for the GU

相关标签:
1条回答
  • 2021-01-15 09:39

    This occurs because you created the Tk main window on a thread and you don't have the UI running on the processes main thread. When you exit the process the cleanup is being done from the process primary thread. The simplest solution for your example here is to create the UI on the primary thread (the processes default thread) and only use another thread for the worker task. If your real application cannot create the UI on the primary thread you will need to look into terminating Tk from its own thread. Deleting the Tcl interpreter might do that for you.

    I modified the example code to show that keeping the UI on the main thread avoids this error message. As you want your worker to be created after the UI is created but before it is running we can use the Tk after method to start the worker once the Tk mainloop is running.

    import time, threading
    from tkinter import *
    from tkinter import messagebox
    
    class Interface:
        def __init__(self):
            #threading.Thread.__init__(self)
            self.attrib1 = "Attrib from Interface class"
            #Main Window
            self.mainWindow = Tk()
            self.mainWindow.geometry("200x200")
            self.mainWindow.title("My GUI Title")
            self.mainWindow.protocol("WM_DELETE_WINDOW", self.quit)
            #Label
            lbCommand = Label(self.mainWindow, text="Hello world", font=("Courier New", 16)).place(x=20, y=20)
    
        #def run(self): 
    
        def start(self): #Start
            self.mainWindow.mainloop()
    
        #The Interface class contains methods that use attributes from itself and attributes from Process class.
        def method1(self): 
            print(self.attrib1)
            print(SecondThread.attrib2)
    
        def quit(self):
            if messagebox.askyesno('App','Are you sure you want to quit?'):
                #In order to use quit function, mainWindow MUST BE an attribute of Interface. 
                self.mainWindow.destroy()
                self.mainWindow.quit()  
    
    class Process(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
            self.attrib2 = "Attrib from Process class"
    
        def run(self):
            global finish
            while not finish:
                print("Proceso infinito")
                #Inside the infinite process a method from Interface class is used.
                GUI.method1()
                time.sleep(3)
    
    finish = False
    #Starts the GUI
    
    GUI = Interface()
    #Starts the infinity process
    SecondThread = Process()
    GUI.mainWindow.after(50, SecondThread.start)   
    #Waits until GUI is closed
    GUI.start()
    #GUI.join()
    print("When GUI is closed this message appears")
    #When GUI is closed we set finish to True, so SecondThread will be closed.
    finish = True
    #After all the program should finish but it raises the error: Tcl_AsyncDelete: async handler deleted by the wrong thread
    
    0 讨论(0)
提交回复
热议问题