Tkinter.Menu() Question

Peter Otten __peter__ at web.de
Sun Jan 4 16:09:35 EST 2004


Adonis wrote:

> I wish to create a popup menu from a list, when it is created they all
> show the same label from the list:
> 
> Months = [0, 'January', 'February', 'March', 'April', 'May', 'June',
>             'July', 'August', 'September', 'October', 'November',
> 'December']
> 
> def _Menu_Click(self, month):
>     print month
> 
> menu = Menu(fraMain, tearoff=0)
> 
> for Month in Months[1:]:
>     menu.add_command(label=Month, command=lambda : _Menu_Click(Month))
> 
> When the menu calls _Menu_Click(...) it always prints 'December'
> 
> Now my understanding is the when an object is created and it is
> replicated, whichever of the modified replications affects all of the
> objects, being that they are just mere references to the original (my
> wording might be off, correct me if I am wrong). How do I avoid this for
> what I am trying to achieve?

(I made some bogus changes so I could ensure it works)

from Tkinter import *

Months = [0, 'January', 'February', 'March', 'April', 'May', 'June',
            'July', 'August', 'September', 'October', 'November',
'December']

root = Tk()

class DontCare:
    def _Menu_Click(self, month):
        print month
dc = DontCare()

mb = Menubutton(root, text="so what")
mb.pack()
menu = mb["menu"] = Menu(mb, tearoff=0) 


for Month in Months[1:]:
    menu.add_command(label=Month, command=lambda m=Month: dc._Menu_Click(m))

root.mainloop()

Note how the instance (dc) is provided with the method (_Menu_Click) in the
lambda (in your real code you will most likely have to replace dc with
self). The real trick is to provide the loop variable Month as the default
value for m in the lambda. m will be bound to the same string as Month when
the lambda is *created*. If you don't do this, the value of the variable
Month will be looked up when the lambda is *called*, which will be always
"December" after the for loop is terminated.

Peter



More information about the Python-list mailing list