[Python-checkins] r58660 - python/trunk/Lib/idlelib/WidgetRedirector.py

kurt.kaiser python-checkins at python.org
Fri Oct 26 02:10:10 CEST 2007


Author: kurt.kaiser
Date: Fri Oct 26 02:10:09 2007
New Revision: 58660

Modified:
   python/trunk/Lib/idlelib/WidgetRedirector.py
Log:
1. Add comments to provide top-level documentation.
2. Refactor to use more descriptive names.
3. Enhance tests in main().


Modified: python/trunk/Lib/idlelib/WidgetRedirector.py
==============================================================================
--- python/trunk/Lib/idlelib/WidgetRedirector.py	(original)
+++ python/trunk/Lib/idlelib/WidgetRedirector.py	Fri Oct 26 02:10:09 2007
@@ -1,17 +1,38 @@
 from Tkinter import *
 
-
 class WidgetRedirector:
 
-    """Support for redirecting arbitrary widget subcommands."""
+    """Support for redirecting arbitrary widget subcommands.
+
+    Some Tk operations don't normally pass through Tkinter.  For example, if a
+    character is inserted into a Text widget by pressing a key, a default Tk
+    binding to the widget's 'insert' operation is activated, and the Tk library
+    processes the insert without calling back into Tkinter.
+
+    Although a binding to <Key> could be made via Tkinter, what we really want
+    to do is to hook the Tk 'insert' operation itself.
+
+    When a widget is instantiated, a Tcl command is created whose name is the
+    same as the pathname widget._w.  This command is used to invoke the various
+    widget operations, e.g. insert (for a Text widget). We are going to hook
+    this command and provide a facility ('register') to intercept the widget
+    operation.
+
+    In IDLE, the function being registered provides access to the top of a
+    Percolator chain.  At the bottom of the chain is a call to the original
+    Tk widget operation.
 
+    """
     def __init__(self, widget):
-        self.dict = {}
-        self.widget = widget
-        self.tk = tk = widget.tk
-        w = widget._w
+        self._operations = {}
+        self.widget = widget            # widget instance
+        self.tk = tk = widget.tk        # widget's root
+        w = widget._w                   # widget's (full) Tk pathname
         self.orig = w + "_orig"
+        # Rename the Tcl command within Tcl:
         tk.call("rename", w, self.orig)
+        # Create a new Tcl command whose name is the widget's pathname, and
+        # whose action is to dispatch on the operation passed to the widget:
         tk.createcommand(w, self.dispatch)
 
     def __repr__(self):
@@ -19,70 +40,87 @@
                                              self.widget._w)
 
     def close(self):
-        for name in self.dict.keys():
-            self.unregister(name)
+        for operation in self._operations:
+            self.unregister(operation)
         widget = self.widget; del self.widget
         orig = self.orig; del self.orig
         tk = widget.tk
         w = widget._w
         tk.deletecommand(w)
+        # restore the original widget Tcl command:
         tk.call("rename", orig, w)
 
-    def register(self, name, function):
-        self.dict[name] = function
-        setattr(self.widget, name, function)
-        return OriginalCommand(self, name)
-
-    def unregister(self, name):
-        if self.dict.has_key(name):
-            function = self.dict[name]
-            del self.dict[name]
-            if hasattr(self.widget, name):
-                delattr(self.widget, name)
+    def register(self, operation, function):
+        self._operations[operation] = function
+        setattr(self.widget, operation, function)
+        return OriginalCommand(self, operation)
+
+    def unregister(self, operation):
+        if operation in self._operations:
+            function = self._operations[operation]
+            del self._operations[operation]
+            if hasattr(self.widget, operation):
+                delattr(self.widget, operation)
             return function
         else:
             return None
 
-    def dispatch(self, cmd, *args):
-        m = self.dict.get(cmd)
+    def dispatch(self, operation, *args):
+        '''Callback from Tcl which runs when the widget is referenced.
+
+        If an operation has been registered in self._operations, apply the
+        associated function to the args passed into Tcl. Otherwise, pass the
+        operation through to Tk via the original Tcl function.
+
+        Note that if a registered function is called, the operation is not
+        passed through to Tk.  Apply the function returned by self.register()
+        to *args to accomplish that.  For an example, see ColorDelegator.py.
+
+        '''
+        m = self._operations.get(operation)
         try:
             if m:
                 return m(*args)
             else:
-                return self.tk.call((self.orig, cmd) + args)
+                return self.tk.call((self.orig, operation) + args)
         except TclError:
             return ""
 
 
 class OriginalCommand:
 
-    def __init__(self, redir, name):
+    def __init__(self, redir, operation):
         self.redir = redir
-        self.name = name
+        self.operation = operation
         self.tk = redir.tk
         self.orig = redir.orig
         self.tk_call = self.tk.call
-        self.orig_and_name = (self.orig, self.name)
+        self.orig_and_operation = (self.orig, self.operation)
 
     def __repr__(self):
-        return "OriginalCommand(%r, %r)" % (self.redir, self.name)
+        return "OriginalCommand(%r, %r)" % (self.redir, self.operation)
 
     def __call__(self, *args):
-        return self.tk_call(self.orig_and_name + args)
+        return self.tk_call(self.orig_and_operation + args)
 
 
 def main():
     root = Tk()
+    root.wm_protocol("WM_DELETE_WINDOW", root.quit)
     text = Text()
     text.pack()
     text.focus_set()
     redir = WidgetRedirector(text)
-    global orig_insert
+    global previous_tcl_fcn
     def my_insert(*args):
         print "insert", args
-        orig_insert(*args)
-    orig_insert = redir.register("insert", my_insert)
+        previous_tcl_fcn(*args)
+    previous_tcl_fcn = redir.register("insert", my_insert)
+    root.mainloop()
+    redir.unregister("insert")  # runs after first 'close window'
+    redir.close()
     root.mainloop()
+    root.destroy()
 
 if __name__ == "__main__":
     main()


More information about the Python-checkins mailing list