tij*_*jko 5 python sockets events tkinter
我有一个简单的聊天客户端,我试图将其Tkinter作为界面使用.我的问题是,当为聊天输入/输出运行mainloopwith 时.after,窗口会冻结并阻塞,直到收到另一条消息.
class Client(Frame):
def __init__(self, **kwargs):
Frame.__init__(self, Tk())
self.pack()
self.lb = Listbox(self, width=100, height=30)
self.lb.pack()
self.show_data = self.lb.after(1000, self.chat_handle)
self.entry = Entry(self)
self.entry.bind('<Return>', self.input_handle)
self.entry.pack(side=BOTTOM, fill=X)
def input_handle(self, event):
msg = self.entry.get()
self.entry.delete(0, 'end')
new_msg = 'privmsg %s :' % self.channel + msg + '\r\n'
self.client.sendall(new_msg)
self.lb.insert(END, self.nick + ' | ' + msg)
def chat_handle(self):
try:
self.data = self.client.recvfrom(1024)
except socket.error:
self.lb.insert(END, "Bad Connection!")
return
if self.data and len(self.data[0]) > 0:
self.lb.insert(END, self.data[0])
elif self.data and len(self.data[0]) == 0:
self.lb.insert(END, "Connection Dropped!")
return
self.show_data = self.lb.after(1000, self.chat_handle)
Run Code Online (Sandbox Code Playgroud)
这段代码缩短了,但显示了相关的相关部分.在调用时,Entry窗口小部件将在长时间内无响应,.after并且在收到消息之前不会响应.
当Entry窗口小部件再次响应时,输入字段包含所有输入的数据,但在"冻结"时间内我不会看到更改.这同样适用于该Listbox部件.
如果我能错过使用某种方法,那么任何人都可以了解为什么这是完全或指出的,我们将不胜感激.
编辑:经过一些更多的研究,它看起来像socket数据在它的被叫和窗口在此期间被冻结时阻塞.
after在给定时间后执行回调函数; 但是,此方法也在主线程中运行.因此,如果某个操作需要比平常更多的时间(在这种情况下,阻塞recvfrom),GUI将无响应,直到执行完整的回调.
为了解决这个问题,一个常见的方法是生成一个新线程并将其与您的Tkinter代码通过一个同步对象进行通信Queue.因此,当您从套接字接收数据时,将数据放入队列中,然后定期检查after回调内的主线程.
这是一个问题,其答案可以适用于使用相同的方法:Tkinter:如何使用线程来防止主事件循环"冻结"
我了解了如何使用select系统调用来检查套接字文件是否已准备好读取。
class Client(Frame):
def __init__(self, **kwargs):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client.connect(("host", port))
self.client.setblocking(0)
Frame.__init__(self, Tk())
self.pack()
self.lb = Listbox(self, width=100, height=30)
self.lb.pack()
self.show_data = self.lb.after(1000, self.chat_handle)
self.entry = Entry(self)
self.entry.bind('<Return>', self.input_handle)
self.entry.pack(side=BOTTOM, fill=X)
def input_handle(self, event):
msg = self.entry.get()
self.entry.delete(0, 'end')
new_msg = 'privmsg %s :' % self.channel + msg + '\r\n'
self.client.sendall(new_msg)
self.lb.insert(END, self.nick + ' | ' + msg)
def chat_handle(self):
socket_data = select.select([self.client], [], [], 0.3) # set timeout on last arg
if socket_data[0]:
try:
self.data = self.client.recvfrom(1024)
except socket.error:
self.lb.insert(END, "Bad Connection!")
return
if self.data and len(self.data[0]) > 0:
self.lb.insert(END, self.data[0])
elif self.data and len(self.data[0]) == 0:
self.lb.insert(END, "Connection Dropped!")
return
self.show_data = self.lb.after(1000, self.chat_hand
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2847 次 |
| 最近记录: |