我对Python(3.x)编程还很陌生,所以我最近决定着手处理我的第一个实际项目,并试图制作一个非常简单的客户机/服务器聊天程序。但是,在我终止客户端或服务器端的tkinter窗口之后,总是会出现一个错误:Tcl_AsyncDelete:async handler被错误的线程删除。在
我已经搜索并找到了关于这个的线索,但是我仍然不明白哪里错了,因为我觉得我找到的其他答案并不真正适合我的应用程序环境。据我所知,这个错误是由于在创建的线程之外终止一个tkinter窗口引起的,但是我看不出这是怎么发生的。请帮忙,提前谢谢!在
import socket
from tkinter import *
from tkinter.messagebox import *
from threading import *
import tkinter.scrolledtext as tkst
import sys
def main():
global c
q = socket.socket()
q.bind(("", 0))
open_port = (q.getsockname()[1])
q.close()
menu = Tk()
menu.configure(bg="black")
menu.iconbitmap("chat.ico")
menu.title("chat")
Label(fg="white", bg="black", text="Set host IP:", font=("Comic Sans", 14)).grid(row=0, column=0, padx=10, pady=10)
Label(fg="white", bg="black", text="Set host port:", font=("Comic Sans", 14)).grid(row=1, column=0, padx=10, pady=10)
Label(fg="white", bg="black", text="Username:", font=("Comic Sans", 14)).grid(row=2, column=0, padx=10, pady=10)
ip_enter = Entry(width=16, font=("Comic Sans", 14))
ip_enter.insert(END, socket.gethostbyname(socket.gethostname()))
port_enter = Entry(width=16, font=("Comic Sans", 14))
port_enter.insert(END, open_port)
user_enter = Entry(width=16, font=("Comic Sans", 14))
ip_enter.grid(row=0, column=1, padx=10, pady=10)
port_enter.grid(row=1, column=1, padx=10, pady=10)
user_enter.grid(row=2, column=1, padx=10, pady=10)
def startup():
try:
host = ip_enter.get()
port = port_enter.get()
username = user_enter.get()
if username == "":
raise ValueError("username cannot be empty")
s = socket.socket()
s.bind((host, int(port)))
menu.destroy()
chat = Tk()
chat.configure(bg="black")
chat.iconbitmap("chat.ico")
chat.title("chat")
def closeout():
s.close()
chat.destroy()
chat.protocol("WM_DELETE_WINDOW", closeout)
chatbox = tkst.ScrolledText(state=DISABLED)
chatbox.grid(row=0, column=0, columnspan=2, padx=2, pady=10)
message = Entry(width=80, font=("Comic Sans", 10))
message.grid(row=1, column=0, padx=10, pady=10)
def sync():
s.listen(1)
global c
c, addr = s.accept()
c.send(("Connected to host " + username + "\n").encode("UTF-8"))
data = (c.recv(1024)).decode("UTF-8")
chatbox.config(state=NORMAL)
chatbox.insert(END, (data))
chatbox.config(state=DISABLED)
chatbox.see("end")
def rec():
while True:
try:
data = (c.recv(1024)).decode("UTF-8")
if data:
chatbox.config(state=NORMAL)
chatbox.insert(END, (data))
chatbox.config(state=DISABLED)
chatbox.see("end")
else:
break
except:
break
rec = Thread(target=rec)
rec.start()
t2 = Thread(target=sync)
t2.start()
def senddata(event):
try:
chatbox.config(state=NORMAL)
if message.get() != "":
mesg = ("<" + username + "> " + message.get() + "\n")
message.delete(0, "end")
chatbox.insert(END, mesg)
chatbox.config(state=DISABLED)
c.send(mesg.encode("UTF-8"))
chatbox.see("end")
except OSError:
useless = 1
send = Button(bg="white", text="Send", font=("Comic Sans", 14))
send.bind("<Button-1>", senddata)
send.grid(row=1, column=1, padx=10, pady=10)
chat.bind("<Return>", senddata)
chat.mainloop()
except OSError:
showerror("Error", "Unable to bind to given IP or Port")
except ValueError:
showerror("Error", "Username field cannot be empty")
connect = Button(bg="white", text="Start", font=("Comic Sans", 14), command=startup)
connect.grid(row=3, column=1, padx=10, pady=10)
menu.mainloop()
if __name__ == '__main__':
main()
我在代码中通过触发垃圾回收解决了这个问题。在
这是一种可能发生此问题的方法,即使您不从线程调用tkinter代码。如果您删除了一个tkinter窗口或小部件,那么Python最终将为这些小部件调用delete方法。当Python的垃圾回收决定在线程运行时释放这些对象时,就会出现问题。换句话说,垃圾回收在线程的上下文中运行,而不是在主线程中运行。在
解决方法:
当您删除tkinter小部件(如按钮)时,会触发垃圾回收。”Delete“可以简单地说,您重复使用了一个用来保存tkinter小部件的变量名。在
在代码中找到释放tkinter资源的位置(删除小部件),并调用Python的垃圾回收来触发一个立即运行的收集。在
这个完全修复了我在多线程环境中运行tkinter时发生的随机aync delee崩溃。在
相关问题 更多 >
编程相关推荐