Tkinter lambda function
(As the 'homework' tag indicates, this is part of a big project in Computer Science.)
I am writing a Jeopardy! simulation in Python with tkinter, and I'm having a big problem regarding the use of the lambda function in buttons. Assume root = Tk()
and categories
is a list.
# Variable to keep the buttons
root._buttons = {}
# Display headers on top of page
for i in range(5):
# Get category name for display in main window
name = categories[i]
b = Label(root, text=fill(name.upper(), 10), width=18, height=3,\
bg="darkblue", fg="white", font=("Helvetica bold", "", 11))
b.grid(row=0, column=i)
# Create list of buttons in that variable (root._buttons)
btnlist = [None]*5
# Display individual questions
for j in range(5):
# Make a button for the question
b = Button(root, text="$" + str(200 * (j+1)), width=8, height=1,
bg="darkblue", fg="orange", font=("Impact", "", 30))
b.cat = name
b.value = 200 * (j + 1)
b.sel = lambda: select(b.cat, b.value)
# Add callback event to button
print(b.cat, b.value, b.sel)
b.config(command=b.sel)
# Add button to window
b.grid(row=j+1, column=i)
# Append to list
btnlist[j] = b
root._buttons[categories[i]] = btnlist
For all of the code, see my little Code Viewer (under construction!)
It's at lambda: select(b.cat, b.value)
where the problem seems to occur, because when I click any button on the board, it always goes to the one last button on the board. I've tried other approaches, unfortunately all using lambda
, and I have not seen any approach that does not involve lambda
.
Change
lambda: select(b.cat, b.value)
to
lambda b = b: select(b.cat, b.value)
In your original code, b
is not a local variable of the lambda
; it is found in enclosing scope. Once the for-loop
is completed, b
retains it last value. That is why the lambda
functions all use the last button.
If you define the lambda to take one argument with a default value, the default value is determined (and fixed) at the time the lambda is defined. Now b
is a local variable of the lambda
, and when the lambda is called with no arguments, Python sets b
to the default value which happily is set to various different buttons as desired.