The tkController Module
Updated October 24, 2006 | March 1998 | Fredrik Lundh
The following module provides a WCK-compatible controller base class. A controller represents a number of event bindings, and the code needed to handle those events. Controllers can be attached to any Tkinter widget.
# File: tkController.py import Tkinter PREFIX = "tkController" class Controller: def __init__(self, master=None): if master is None: master = Tkinter._default_root assert master is not None self.tag = PREFIX + str(id(self)) def bind(event, handler): master.bind_class(self.tag, event, handler) self.create(bind) def install(self, widget): widgetclass = widget.winfo_class() # remove widget class bindings and other controllers tags = [self.tag] for tag in widget.bindtags(): if tag != widgetclass and tag[:len(PREFIX)] != PREFIX: tags.append(tag) widget.bindtags(tuple(tags)) def create(self, handle): # override if necessary # the default implementation looks for decorated methods for key in dir(self): method = getattr(self, key) if hasattr(method, "tkevent") and callable(method): handle(method.tkevent, method) ## # Simple event decorator for Python 2.4 and later. def bind(event): def decorator(func): func.tkevent = event return func return decorator
To create a specific controller, subclass the Controller base class, implement one or more event handler methods, and use the bind decorator to flag them as such:
class myController(Controller): @bind("<Button-1>") # binds method to event def click(self, event): print "click at", event.x, event.y frame = Frame() frame_controller = myController(frame) frame_controller.install(frame)
If you’re using an older Python version, or have special requirements, you can override the create method instead:
class myController(Controller): def create(self, bind): bind("<Button-1>", self.click) def click(self, event): print "click at", event.x, event.y frame = Frame() frame_controller = myController(frame) frame_controller.install(frame)
The Controller constructor calls the create method, passing in a callable bind handler that should be used to set up event bindings.
To install a controller on a widget, create an instance of the controller, and call the install method. This removes the existing controller from the widget, if any, and also removes all standard widget bindings. When install returns, all events will be routed to the new controller.
You can switch controllers at any time (for example to switch between different tools).
Examples
Drawing Canvas Items
This example uses a simple controller to draw red rectangles on a Tkinter canvas. The example creates two canvas widgets, and attaches the same controller instance to both. This works because the user can only draw on one canvas at a time, and the controller can use the widget event attribute to distinguish between the widgets.
import Tkinter from tkController import Controller, bind class myController(Controller): @bind("<Button-1>") def click(self, event): self.anchor = event.x, event.y self.item = None @bind("<B1-Motion>") def drag(self, event): bbox = self.anchor + (event.x, event.y) if self.item is None: self.item = event.widget.create_rectangle(bbox, fill="red") else: event.widget.coords(self.item, *bbox) # create widgets canvas1 = Tkinter.Canvas(bg="white") canvas1.pack(side="left") canvas2 = Tkinter.Canvas(bg="black") canvas2.pack(side="left") canvas_controller = myController() canvas_controller.install(canvas1) canvas_controller.install(canvas2) Tkinter.mainloop()
More examples to be added…