From: aa8vb at vislab.epa.gov (Randall Hopper)
Date: Thu, 22 Apr 1999 11:35:16 -0400
Subject: Callbacks and "callable" objects
Message-ID: <19990422113516.A278137@vislab.epa.gov>
Content-Length: 2224
X-UID: 1300                                                  

     A while back I asked how to pass parameterized callbacks to Tkinter.
Now I need to explore how best to do partial resolution of callback
arguments.  For example, define values for arguments 1 and 2 at
registration time, but leave argument 3 to be populated by Tkinter.

     Probably makes no sense.  So let me use an example:

-------------------------------------------------------------------------------

For simple callbacks you can use a lambda or function wrapper:

  def SetColor( color ):
    print color
  
  wgt1.configure( command = lambda color="red" : SetColor(color) )
  wgt1.configure( command = lambda color="blue": SetColor(color) )

One suggestion Thomas Heller offered before was to use a callable object
instead; this gives a much simpler appearance:

  def SetColor( color ):
    print color
  
  wgt1.configure( command = Call( SetColor, "red"  ) )
  wgt1.configure( command = Call( SetColor, "blue" ) )

(Call class source attached below in case you're interested).

-------------------------------------------------------------------------------

The wrinkle now is what if SetColor is an event callback (i.e. Tkinter
provides an event argument):

  def SetColor( color, event ):
    print color

this breaks the callable object form:
  wgt1.configure( command = Call( SetColor, "red"  ) )

with Tkinter giving:
  TypeError: too many arguments; expected 1, got 2

So my quetsion is, can the "callable object" be used?  Or do I have to fall
back to a lambda wrapper?

Thanks,

Randall



-------------------------------------------------------------------------------
class Call:
  """Instances of this class store a function as well as a list of arguments.
     When they are called, the function will be called together with the
     arguments used for creating the instance.
     Slightly different than lambda, but nicer syntax."""

  def __init__ (self, func, *args):
    self.func = func             # save the function (or bound method,or ...)
    self.args = args             # save the arguments to use 
  def __call__ (self):
    apply (self.func, self.args) # call function, using args as arguments.
-------------------------------------------------------------------------------





