2014-11-22 339 views
2

我聽說Python中的線程不容易處理,它們變得更加和tkinter糾纏在一起。Tcl_AsyncDelete錯誤多線程Python

我有以下問題。我有兩個類,一個用於GUI,另一個用於無限處理(我必須爲這兩個類使用類)。首先,我啓動GUI類,然後啓動無限過程的類。我希望當你關閉GUI時,它也完成了無限的過程,程序結束。

代碼的簡化版本如下:

import time, threading 
from tkinter import * 
from tkinter import messagebox 

class Interface(threading.Thread): 
    def __init__(self): 
     threading.Thread.__init__(self) 
     self.attrib1 = "Attrib from Interface class" 

    def run(self): 
     #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) 
     #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() 
GUI.start() 
#Starts the infinity process 
SecondThread = Process() 
SecondThread.start()  
#Waits until GUI is closed 
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

「#After所有程序要完成,但它引發的錯誤:Tcl_AsyncDelete:由錯誤的線程異步刪除處理程序」不顯示我在python3.3 Ubuntu Linux系統。 – 2014-11-22 03:54:41

+0

看來這個錯誤只發生在Windows ..奇怪.. – 2014-11-22 05:33:42

回答

4

發生這種情況是因爲您在線程上創建了Tk主窗口,並且您沒有在進程主線程上運行UI。當您退出進程時,將從進程主線程完成清理。這裏最簡單的解決方案是在主線程(進程默認線程)上創建用戶界面,並只爲工作任務使用另一個線程。如果您的真實應用程序無法在主線程上創建UI,則需要從自己的線程中查看終止的Tk。刪除Tcl解釋器可能會爲你做到這一點。

我修改了示例代碼,以顯示將UI保留在主線程上以避免此錯誤消息。由於您希望在創建UI之後但在運行之前創建工作人員,因此一旦Tk mainloop正在運行,我們就可以使用Tk after方法啓動工作人員。

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

「如果你真正的應用程序無法在主線程上創建UI,你將需要從它自己的線程中查看終止Tk。刪除Tcl解釋器可能會爲你做到這一點「。任何提示?我無法在主線程上運行主循環,並且必須在相同的情況下創建UI。我將如何繼續在我創建的線程中終止UI? – FichteFoll 2016-04-09 14:05:38

+3

如果您在'.mainloop()之後調用'.quit()','Tcl_AsyncDelete'錯誤將消失。 – Eric 2016-11-11 16:58:59