I have a menubutton, which when clicked should display a menu containing a specific sequence of strings. Exactly what strings are in that sequence, we do not know until runtime, so the menu that pops up must be generated at that moment. Here's what I have:
class para_frame(Frame):
def __init__(self, para=None, *args, **kwargs):
# ...
# menu button for adding tags that already exist in other para's
self.add_tag_mb = Menubutton(self, text='Add tags...')
# this menu needs to re-create itself every time it's clicked
self.add_tag_menu = Menu(self.add_tag_mb,
tearoff=0,
postcommand = self.build_add_tag_menu)
self.add_tag_mb['menu'] = self.add_tag_menu
# ...
def build_add_tag_menu(self):
self.add_tag_menu.delete(0, END) # clear whatever was in the menu before
all_tags = self.get_article().all_tags()
# we don't want the menu to include tags that already in this para
menu_tags = [tag for tag in all_tags if tag not in self.para.tags]
if menu_tags:
for tag in menu_tags:
def new_command():
self.add_tag(tag)
self.add_tag_menu.add_command(label = tag,
command = new_command)
else:
self.add_tag_menu.add_command(label = "<No tags>")
The important part is the stuff under "if menu_tags:" -- Suppose menu_tags is the list ['stack', 'over', 'flow']. Then what I want to do is effectively this:
self.add_tag_menu.add_command(label = 'stack', command = add_tag_stack)
self.add_tag_menu.add_command(label = 'over', command = add_tag_over)
self.add_tag_menu.add_command(label = 'flow', command = add_tag_flow)
where add_tag_stack() is defined as:
def add_tag_stack():
self.add_tag('stack')
and so on.
The problem is, the variable 'tag' takes on the value 'stack' and then the value 'over' and so on, and it doesn't get evaluated until new_command is called, at which point the variable 'tag' is just 'flow'. So the tag that gets added is always the last one on the menu, no matter what the user clicks on.
I was originally using a lambda, and I thought maybe explicitly defining the function as above might work better. Either way the problem occurs. I've tried using a copy of the variable 'tag' (either with "current_tag = tag" or using the copy module) but that doesn't solve it. I'm not sure why.
My mind is starting to wander towards things like "eval" but I'm hoping someone can think of a clever way that doesn't involve such horrible things.
Much thanks!
(In case it's relevant, Tkinter.__version__ returns '$Revision: 67083 $' and I'm using Python 2.6.1 on Windows XP.)