Home > Software engineering >  Prevent a queue of events in tkinter
Prevent a queue of events in tkinter

Time:03-10

I have made a GUI using TkInter. Now I am trying to perform an action after a key press. However, I don't want the action to perform twice when I click the button twice. But rather, the program should wait until the previous action is finished before it starts waiting for the next key press. I cannot seem to achieve this, even thought the command handler returns "break". See below a minimal working example, where if you press the <Left> button multiple times, the code also executes multiple times. How should I change the code to achieve the desired performance?

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()

CodePudding user response:

When You execute Your event_handler with time.sleep(1), You are effectively blocking any other event execution. But event triggers are accumulating and executed one after another how each event_handler starts and ends. It creates effect of serial execution of event_handler.

What You want is to set some flag which will indicates Your event state. Then You have to process all accumulated events before Your return from event_handler. This will cause all events to execute, but immediately return, because flag is set to True: event is running.

Here is code snippet:

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()
  • Related