Home > Mobile >  Tkinter Event Binding
Tkinter Event Binding

Time:07-29

Is it possible to make an event fire in a different order. For instance, if I add a MouseWheel listener to a Text widget, I will get the event before the scrolling has even been applied. Is there a way to make my bind come last?

import tkinter as tk

root = tk.Tk()

def wheel(event): print('this will fire before the movement has happened')

t=tk.Text(root)
t.pack(fill=tk.BOTH, expand=True)
t.bind('<MouseWheel>', wheel)

root.mainloop()

SIDENOTE: I already have a system where I simply hijack the entire MouseWheel event and handle the scroll myself. That's not the answer I'm looking for. I seriously want my event to come after it is handled internally.

CodePudding user response:

You can change the order in which callbacks for a specific event are processed, but you can't change the order of the events themselves.

There's already a question on Stackoverflow that asks something similar, and it has an answer that includes an example that illustrates how to change the order that callbacks are handled. See this answer to the question How to bind self events in Tkinter Text widget after it will binded by Text widget?

That answer mentions tkinter's bind tags. There's another question that goes into a bit of detail about how bindings are processed. See this answer to the question Basic query regarding bindtags in tkinter

CodePudding user response:

One method is to create a proxy and filter the events, as below:

import tkinter as tk
from contextlib  import suppress

class Text(tk.Text):
    def __init__(self, master):
        tk.Text.__init__(self, master)
        
        self.bind('<MouseWheel>', self.__handler)
        
        self._p = self._w   "_orig"
        self.tk.call("rename", self._w, self._p)
        self.tk.createcommand(self._w, self._proxy) 
        
    def _proxy(self, cmd, *args) -> None:
        targ = ""

        with suppress(tk.TclError): targ = self.tk.call((self._p, cmd)   args)
        
        if cmd=='yview' and 'scroll' in args: self.after_idle(self.__handler, None, args)
            
        return targ   
        
    def __handler(self, event, *args) -> None:
        if event: print('from bind')
        else:     print('from proxy')


root = tk.Tk()

t=Text(root)
t.pack(fill=tk.BOTH, expand=True)

root.mainloop()
  • Related