防止 tkinter 中的事件队列

Prevent a queue of events in tkinter

我已经使用 TkInter 制作了一个 GUI。 现在我试图在按键后执行一个动作。 但是,我不希望在单击按钮两次时执行两次操作。 相反,程序应该等到上一个动作完成后才开始等待下一个按键。 我似乎无法实现这一点,即使是命令处理程序 returns "break"。 请参阅下面的最小工作示例,如果您多次按下 <Left> 按钮,代码也会执行多次。我应该如何更改代码以达到所需的性能?

import tkinter as tk
import time

class App(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self)
        # Create handler
        def event_handler(event):
            print('One run for event', event)
            time.sleep(1)
            print('Done')
            return "break"
        # Button
        self.button = tk.Button(
            master=self,
            text='Test',
            command = event_handler
            )
        self.button.grid()
        self.bind('<Left>', event_handler)
        self.focus()

if __name__ == "__main__":
    root = tk.Tk()
    root.title("TestTool")
    # Start application
    app = App(root)
    app.pack(fill="both", expand=True)
    root.mainloop()

当您使用 time.sleep(1) 执行您的 event_handler 时,您实际上是在阻止任何其他事件的执行。但是事件触发器是一个接一个地累积和执行的,每个event_handler是如何开始和结束的。它创建 event_handler.

串行执行的效果

你想要的是设置一些标志来指示你的事件状态。然后你必须处理你的 return 来自 event_handler 之前的所有累积事件。这将导致所有事件执行,但立即 return,因为标志设置为 Trueevent is 运行.

这是代码片段:

import time
import tkinter as tk


class App(tk.Frame):

    event_running = False

    def __init__(self, parent):
        tk.Frame.__init__(self)

        # Create handler
        def event_handler(event=None):
            # Check if event is running
            if self.event_running:
                return False
            # Lock event until it's finished
            self.event_running = True
            print('One run for event', event)
            time.sleep(1)
            print('Done')
            # Update all pending events
            self.update()
            self.update_idletasks()
            # Release event handler
            self.event_running = False
            return

        # Button
        self.button = tk.Button(
            master=self,
            text='Test',
            command=event_handler
        )
        self.button.grid()
        self.bind('<Left>', event_handler)
        self.focus()


if __name__ == "__main__":
    root = tk.Tk()
    root.title("TestTool")
    # Start application
    app = App(root)
    app.pack(fill="both", expand=True)
    root.mainloop()