0

I have a Python Tkinter GUI where some menu items are added in a loop (based on workers that are running). When I select one of these menu items, I always get the value of the last item. To simplify things and do a test, I made a test file and it does the same thing. Note that the menu looks fine, each label shows. If anyone can think of a work around, I would really appreciate the help.

from tkinter import Tk
from tkinter import *
import tkinter.messagebox
import tkinter.simpledialog

def popup(msg='No message'):
    tkinter.messagebox.showinfo(msg)

if __name__ == '__main__':
    root = Tk()
    menu_bar = tkinter.Menu(root)
    root.config(menu=menu_bar)
    filemenu = tkinter.Menu(menu_bar)
    stopworkermenu = tkinter.Menu(filemenu, tearoff=False)
    menu_bar.add_cascade(label='File', menu=filemenu)
    filemenu.add_cascade(label="Stop Worker", menu=stopworkermenu)

    # these lines result in 'Delta' always being returned:
    menu_list = ['Alpha', 'Beta', 'Gamma', 'Delta']
    for m in menu_list:
       stopworkermenu.add_command(label=m, command=lambda: popup(m)

    # when these lines are used, each item is returned correctly:
    # stopworkermenu.add_command(label='Alpha', command=lambda: popup('Alpha')
    # stopworkermenu.add_command(label='Beta', command=lambda: popup('Beta')
    # stopworkermenu.add_command(label='Gamma', command=lambda: popup('Gamma')
    # stopworkermenu.add_command(label='Delta', command=lambda: popup('Delta')

    mainloop()
stovfl
  • 14,998
  • 7
  • 24
  • 51
Terri Simon
  • 127
  • 1
  • 10
  • 1
    Read about [what-is-lambda-binding-in-python](https://stackoverflow.com/questions/160859/what-is-lambda-binding-in-python) – stovfl Mar 04 '19 at 21:53
  • @stovfl Thanks for the information explaining why this happens. We did figure out a way to make the call that works. See my answer. – Terri Simon Mar 05 '19 at 14:09

1 Answers1

0

We found a way to make this work. Change

stopworkermenu.add_command(label=m, command=lambda: popup(m)

to the following:

stopworkermenu.add_command(label=m, command=lambda boundm=m: popup(boundm)

This seems to bind the parameter to the lambda function at creation rather than at the time of the call.

Terri Simon
  • 127
  • 1
  • 10