Tkinter .after method freezing window?

前端 未结 2 1003
日久生厌
日久生厌 2021-01-03 02:03

I have a simple chat client that I was attempting to get working with Tkinter as the interface. My problem is that when running the mainloop with

相关标签:
2条回答
  • 2021-01-03 02:32

    I learned about using select to make system calls to check if a socket file is ready to be read.

    How to set timeout on python's 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 讨论(0)
  • 2021-01-03 02:49

    after executes the callback function after the given time; however, this method also runs in the main thread. So if there is an operation that takes more time than usual (in this case, the blocking recvfrom), the GUI will be unresponsive until the complete callback is executed.

    To solve this, a common recipe is to spawn a new thread and communicate it with your Tkinter code with a synchronized object like a Queue. Thus, you put the data in the queue when you receive it from the socket, and then check periodically in the main thread inside the after callback.

    This is a question whose answer can be adapted to use the same approach: Tkinter: How to use threads to preventing main event loop from "freezing"

    0 讨论(0)
提交回复
热议问题