Python 2.7 如果在程序的其他地方调用了空闲后,单击tkinter optionmenu会挂起

Python 2.7 如果在程序的其他地方调用了空闲后,单击tkinter optionmenu会挂起,python-2.7,tkinter,callback,optionmenu,idle-processing,Python 2.7,Tkinter,Callback,Optionmenu,Idle Processing,我有一个GUI,可以在消息到达并被几个WebSocket排队时连续处理消息。此函数使用after_idle设置对自身的回调,以使进程永久化,如下所示: def process_queue(self, flush=False): ''' Check for new messages in the queue periodically. Sets up callback to itself to perpetuate the process.

我有一个GUI,可以在消息到达并被几个WebSocket排队时连续处理消息。此函数使用after_idle设置对自身的回调,以使进程永久化,如下所示:

 def process_queue(self, flush=False):
        '''
        Check for new messages in the queue periodically.
        Sets up callback to itself to perpetuate the process.
        '''
        if flush:
            while not self.queue.empty():
                self.get_msg()
        else:
            self.get_msg()
            self.master.after_idle(self.process_queue)
我在GUI上有一个OptionMenu小部件,它会在单击时挂起并导致程序崩溃:

self.plotind = tk.StringVar()
self.plotind.set('MACD')
options = ['MACD']
self.indopts = tk.OptionMenu(self.analysis_frame, self.plotind, *[option for option in options])
self.indopts.grid(row=1, column=1)
如果我将after_idle更改为just after,它工作正常

我认为这是因为点击一个OptionMenu实际上设置了自己的after_idle调用来打开菜单,然后它将与我在进程队列中的菜单竞争


如果需要的话,我当然可以在我的函数中使用after-它在处理队列时可能不是最快的,但它不是世界末日。但是有没有更优雅的方式来处理这个问题呢?当然,大多数GUI应该能够处理在存在OptionMenu时在某处调用after\u idle的问题?

一般来说,您不应该通过after\u idle调用after\u idle的函数来调用after\u idle

原因如下:

一旦tkinter开始处理空闲队列,它将不会停止,直到队列为空。如果队列中有一个项目,tkinter会将该项目取出并调用该函数。如果该函数向队列中添加了某些内容,则队列不再为空,因此tkinter将处理新项目。如果这个新项目将某个内容放入空闲队列,那么tkinter将处理该内容,依此类推。队列永远不会变为空,tkinter也永远不会有机会执行除服务此队列之外的任何其他操作

一种常见的解决方案是在两次之后使用,这样队列就有机会变为空,从而允许tkinter处理其他非空闲事件

例如,与此相反:

self.master.after_idle(self.process_queue)
。。。这样做:

self.master.after_idle(self.master.after, 1, self.process_queue)

这会为队列创建一个小窗口,使其变为空,从而允许tkinter在再次调用self.process_queue之前处理其他非空闲事件,例如重新绘制屏幕的请求

空闲命令不竞争。他们只是简单地在队列中放置一些东西,然后立即返回。有趣,但令人费解。我猜如果GUI将其所有空闲时间都花费在process_queue中,那么只有在调用process_queue之间我碰巧单击它时,OptionMenu才会打开?如果我在insead之后使用,一切都很好,这表明有些东西在竞争,但可能只是程序几乎从不在mainloop中,这将需要打开OptionMenu?我将试着做一个MWE。