This recipes tries to solve the problem of bind_all and unbind_all for tkinter.
When a callback is registered using bind_all method and later it's unregistered using unbind_all, all the callbacks are deleted for the "all" tag event. This makes difficult to register and unregister only one callback at a time. This recipes tries to solve this problem.
Observe the difference between the code below and the recipe. With the code below, when the user clicks nothing happens. But with my recipe it's possible to bind and unbind specific callbacks.
try:
from Tkinter import Tk, Frame
except ImportError:
from tkinter import Tk, Frame
root = Tk()
f = Frame(root, width= 300, height=300)
f.pack()
def callback1(event):
print("callback1")
def callback2(event):
print("callback2")
def callback3(event):
print("callback3")
root.bind_all("<1>", callback1, add="+")
f.bind_all("<1>", callback2, add="+")
f.bind_all("<1>", callback3, add="+")
f.unbind_all("<1>")
root.mainloop()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | from __future__ import print_function
import sys
import collections
import functools
_handlers = collections.defaultdict(list)
def _run_handlers(list_of_handlers, event):
exc_info = None
for func in list_of_handlers:
try:
func(event)
except SystemExit:
exc_info = sys.exc_info()
except:
import traceback
print("Error in global_binding._run_handlers:", file=sys.stderr)
traceback.print_exc()
exc_info = sys.exc_info()
if exc_info is not None:
raise exc_info[0], exc_info[1], exc_info[2]
def global_bind(w, event, func, add=None):
root = w.nametowidget(".")
handlers_of_event = _handlers[event]
if len(handlers_of_event) == 0:
root.bind_all(event, functools.partial(_run_handlers, handlers_of_event))
if add == "+":
handlers_of_event.append(func)
else:
handlers_of_event[:] = [func]
return func
def global_unbind(w, event, func):
handlers_of_event = _handlers[event]
handlers_of_event.remove(func)
if len(handlers_of_event) == 0:
w.unbind_all(event)
if __name__ == "__main__":
try:
from Tkinter import Tk, Frame
except ImportError:
from tkinter import Tk, Frame
root = Tk()
f = Frame(root, width= 300, height=300)
f.pack()
def callback1(event):
print("callback1")
def callback2(event):
print("callback2")
def callback3(event):
print("callback3")
global_bind(root, "<1>", callback1, add="+")
global_bind(f, "<1>", callback2, add="+")
global_bind(f, "<1>", callback3, add="+")
global_unbind(f, "<1>", callback1)
root.mainloop()
|