| 
									
										
										
										
											2008-05-20 07:13:37 +00:00
										 |  |  | from Tkinter import * | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class WidgetRedirector: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |     """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. | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |     def __init__(self, widget): | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |         self._operations = {} | 
					
						
							|  |  |  |         self.widget = widget            # widget instance | 
					
						
							|  |  |  |         self.tk = tk = widget.tk        # widget's root | 
					
						
							|  |  |  |         w = widget._w                   # widget's (full) Tk pathname | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |         self.orig = w + "_orig" | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |         # Rename the Tcl command within Tcl: | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |         tk.call("rename", w, self.orig) | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |         # 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: | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |         tk.createcommand(w, self.dispatch) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return "WidgetRedirector(%s<%s>)" % (self.widget.__class__.__name__, | 
					
						
							|  |  |  |                                              self.widget._w) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def close(self): | 
					
						
							| 
									
										
										
										
											2007-12-18 21:56:09 +00:00
										 |  |  |         for operation in list(self._operations): | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |             self.unregister(operation) | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |         widget = self.widget; del self.widget | 
					
						
							|  |  |  |         orig = self.orig; del self.orig | 
					
						
							|  |  |  |         tk = widget.tk | 
					
						
							|  |  |  |         w = widget._w | 
					
						
							|  |  |  |         tk.deletecommand(w) | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |         # restore the original widget Tcl command: | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |         tk.call("rename", orig, w) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |     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) | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             return function | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |     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) | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             if m: | 
					
						
							| 
									
										
										
										
											2003-07-09 18:48:24 +00:00
										 |  |  |                 return m(*args) | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |                 return self.tk.call((self.orig, operation) + args) | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |         except TclError: | 
					
						
							|  |  |  |             return "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class OriginalCommand: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |     def __init__(self, redir, operation): | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |         self.redir = redir | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |         self.operation = operation | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |         self.tk = redir.tk | 
					
						
							|  |  |  |         self.orig = redir.orig | 
					
						
							|  |  |  |         self.tk_call = self.tk.call | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |         self.orig_and_operation = (self.orig, self.operation) | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |         return "OriginalCommand(%r, %r)" % (self.redir, self.operation) | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __call__(self, *args): | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |         return self.tk_call(self.orig_and_operation + args) | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def main(): | 
					
						
							|  |  |  |     root = Tk() | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |     root.wm_protocol("WM_DELETE_WINDOW", root.quit) | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |     text = Text() | 
					
						
							|  |  |  |     text.pack() | 
					
						
							|  |  |  |     text.focus_set() | 
					
						
							|  |  |  |     redir = WidgetRedirector(text) | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |     global previous_tcl_fcn | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |     def my_insert(*args): | 
					
						
							|  |  |  |         print "insert", args | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |         previous_tcl_fcn(*args) | 
					
						
							|  |  |  |     previous_tcl_fcn = redir.register("insert", my_insert) | 
					
						
							|  |  |  |     root.mainloop() | 
					
						
							|  |  |  |     redir.unregister("insert")  # runs after first 'close window' | 
					
						
							|  |  |  |     redir.close() | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  |     root.mainloop() | 
					
						
							| 
									
										
										
										
											2007-10-26 00:10:09 +00:00
										 |  |  |     root.destroy() | 
					
						
							| 
									
										
										
										
											2000-08-15 01:13:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     main() |