Tkinter After window freezing method?

I have a simple chat client that I'm trying to work with Tkinter as an interface. My problem is that when I start mainloop with .after for chat I / O, the window freezes and locks until another message is received.

 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) 

This code block is abbreviated, but shows the parts involved. The Entry widget will stop responding for long periods of time until .after is called and will not respond until a message is received.

When the Entry widget reacts again, the input field has all the data that has been entered, but I will not see the changes during the "frozen" time. The same goes for the Listbox widget.

If someone can shed some light on why this is accurate or indicate if I skipped a method, it would be very helpful here.

EDIT: after several studies, its appearance, similar to socket data, is blocked whenever its callers and windows freeze during this time.

+4
source share
2 answers

I learned about using select to make system calls to check if the socket file is ready for reading.

How to set timeout on python socket recv method?

 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 
0
source

after performs a callback function after a specified time; however, this method also works in the main thread. Therefore, if there is an operation that takes longer than usual (in this case recvfrom lock), the GUI will not respond to requests until a full callback is made.

To solve this problem, a common recipe is to create a new thread and pass it along with your Tkinter code with a synchronized object like Queue . This way you put data in the queue when you get it from the socket, and then periodically check in the main thread inside the after callback.

This is a question, the answer to which can be adapted to use the same approach: Tkinter: How to use threads to prevent the main event loop from “freezing”

+5
source

Source: https://habr.com/ru/post/1485343/


All Articles