使用after()

时间:2018-03-19 19:06:37

标签: python tkinter callback

我在tkinter中有一个应用程序,可以同时从多个websockets接收消息。为了顺序处理这些并避免竞争条件,我将每条消息添加到Queue,并按顺序处理它们,如下所示:

def queue_msg(self, msg):
    self.queue.put(msg)

def process_queue(self):
    try:
        msg = self.queue.get(0)
    except Queue.Empty:
        pass
    else:
        ...do stuff...
    self.master.after(10, self.process_queue)

只要应用程序正在运行,self.process_queue()函数就会一直调用自身,以便在后台顺利处理所有邮件。到现在为止还挺好。

我在代码中有几个操作,我需要暂停处理新消息。当这些发生时,我希望应用程序1)停止向队列添加新消息,2)处理队列中已有的所有消息,3)执行操作,以及4)再次开始向队列添加消息。删除临时到达的邮件很好。

我的第一次尝试是定义一个类变量self.pause,让这些操作将其设置为True,并在接收新消息时检查这种情况:

def queue_msg(self, msg):
    if not self.pause:
        self.queue.put(msg)

def process_queue(self):
    try:
        msg = self.queue.get(0)
    except Queue.Empty:
        pass
    else:
        ...do stuff...
    self.master.after(10, self.process_queue)

def sensitive_operation(self):
    self.pause = True
    while self.queue.qsize() > 0:
        continue
    ....do stuff....
    self.pause = False

但这失败了。 qsize()已经为0,在这种情况下self.pause出现False通常会在sensitive_operation()退出后保持continue,或者它会卡在after()的无限循环中}。

显然我误解了self.pause方法的某些内容,因为pause的明显更改并未通过各种回调进行一致的传播。有人可以帮助我了解幕后发生的事情,并建议在必要时暂停和清空队列的更好方法吗?

这是一个最小的工作示例。为了模拟来自websocket的消息到达,我使用process_message()函数在处理队列时随机地向队列添加消息。按下continue按钮大部分时间都可以正常工作,但是如果你将它混搭几次,它最终会挂在import Tkinter as tk import ttk import Queue import numpy as np class App(tk.Frame): def __init__(self, parent): parent.deiconify() self.parent = parent self.queue = Queue.Queue() self.pause = False self.parent.after(1000, self.process_message) self.pause_button = tk.Button(parent, text='Pause', command = self.pause_and_empty) self.pause_button.pack() def queue_message(self, message): if not self.pause: self.queue.put(message) def process_message(self): try: message = self.queue.get(0) except Queue.Empty: pass else: print message rand = np.random.rand() if rand < 0.2: self.queue_message('test message: {0}'.format(rand)) self.parent.after(10, self.process_message) def pause_and_empty(self): self.pause = True while self.queue.qsize() > 0: print 'stuck!' continue print 'made it!' self.pause = False def main(): root = tk.Tk() root.withdraw() app = App(root) root.mainloop() if __name__=="__main__": main()

pause_and_empty

编辑2:根据第一个答案,对def pause_and_empty(self): self.pause = True if self.queue.qsize() > 0: self.parent.after(10, self.pause_and_empty) print 'made it!' 函数进行以下调整似乎可以解决问题:

textClock.text = hour + ":" + minute + ":" + second;

1 个答案:

答案 0 :(得分:1)

当读取widget.after(milliseconds, callback, *args)时,它会在 callback之后将*argsmilliseconds 调用mainloop的计时器事件排队。方法完成后, 返回process_message行。

示例中的队列永远不会停止,因为对self.pause的调用永远不会停止,因为它为什么要这样做? False设置为process_message,但True从不检查它是否为manipulateDOM()