Tkinter: passing parameters to menu commands

Kent Johnson kent3737 at yahoo.com
Sat Jan 8 11:43:43 EST 2005


Philippe C. Martin wrote:
>>>menu.add_cascade(label="File", menu=filemenu)
>>>filemenu.add_command(label="New", command=lambda: callback('New'))
>>>filemenu.add_command(label="Open...", command=lambda:
> 
>>>Of course you could do this with named forwarding functions if you
> 
> prefer
> 
> 
> I'm not sure what 'named forwarding functions' 

Bad choice of terminology, I just mean you can explicitly define
def handleNew:
   callback('New')

etc.

are but I'm actually in a
> class and when applying your suggestion in the following manner,
> everything works (THANKS!)
> 
> ****************************
> def __Dec(self,p_string):
>   for i in p_string:
>     self.__Insert(i)
> .
> .
> .
> #menu creation
> l_dec.add_command(label = 'ATR', command=lambda: self.__Dec('ATR'))
> l_dec.add_command(label = 'IN', command=lambda:self.__Dec('IN'))
> .
> .
> .
> ****************************
> 
> Yet I have a question:
> 
> If I replace the menu creation code as below, and since __Insert appends
> the string p_string into a text widget that is created _after_ the menu
> creation; the method __Dec seems to be called at the menu creation and
> I get an error in __Insert because the test widget is equal to None.
> 
> My reflexes of C programmer tell me that command=self.__Dec.... just
> passes a method pointer (sorry I said it) to add_command - yet it does
> not seem to be so.
 >
 > What is actually going on ?
 >
 >
 > #menu creation
 > l_dec.add_command(label = 'ATR', command=self.__Dec('ATR'))
 > l_dec.add_command(label = 'IN', command=self.__Dec('IN'))

self.__Dec is a reference to the function. It is similar to a method pointer so you don't need to 
apologize ;) The name of a function without the () is a reference. When you append () it becomes a 
call to the referenced function.

The command parameter for the menu must be a reference to a function. The function is called with no 
arguments when the menu is invoked.

So, you need a function of no arguments to handle the command. For example,

def handleMenu():
   print 'Handled'

filemenu.add_command(label="New", command=handleMenu)

Note there is no () after handleMenu. 'command' is bound to the function object; the function is not 
called until later.

OK, now suppose you want to pass a parameter to handleMenu?

def handleMenu(menuName):
   print 'Handled', menuName

Now what do you put in the command parameter? This won't work because you are *calling* handleMenu 
and assigning the result of the call (in this case the value None) to 'command':

filemenu.add_command(label="New", command=handleMenu('New')) # WRONG

You need a new function of zero arguments to bind to 'command'. Here is one way to do it:

def handleNew():
   handleMenu('New')

filemenu.add_command(label="New", command=handleNew) # OK

Note, again, no () after handleNew. 'command' is bound to the function object again.


OK, what about lambda? lambda is a way to create a simple anonymous function. One simple use of 
lambda is to make a new function that binds a parameter to another function.

lambda: handleMenu('New')

defines a function that does the same thing as handleNew. The value of the lambda expression is the 
function object. So

filemenu.add_command(label="New", command=lambda: handleMenu('New')) # OK

is another way to get the result you want.

Kent



More information about the Python-list mailing list