1

Using tkinter and python to build a GUI and I'm adding buttons using globals() based off a list of room_types. However, the variable I'm passing into the button's command is always the last item on the list, even though every other instance of using room_type[i] correlates to the correct element.

This is what I'm having problems with.

from tkinter import *

root = Tk()

room_type = ['kitchen', 'living_room', 'bedroom', 'bathroom', 'study', 'laundry', 'dining_room']


def new_room(r):
    print(r)


for i in range(len(room_type)):
    globals()[f'{room_type[i]}_add'] = Button(root, text='Add a ' + room_type[i],
                                              command=lambda: new_room(r=room_type[i]))
    globals()[f'{room_type[i]}_add'].grid(row=1, column=i)

root.mainloop()

It makes 7 buttons, each with text that indicates the different room types, but for some reason, r always equals the last element in the list. In this case, dining_room.

  • You are not storing the current value of i with "lambda: new_room(r=room_type[i]))", so when you click the button it uses the value that i is when you click it (which is the value it ended up at at the end of the range loop) – Chris Welton Sep 12 '21 at 01:46
  • Ah, I see. Is there any way to set r to equal room_type[i] at that specific iteration? @ChrisWelton – progress456 Sep 12 '21 at 01:50
  • 1
    command=lambda pi=i: new_room(r=room_type[pi])) (I just called it pi like private i, but that's the idea. You have to capture it in the lambda declaration) – Chris Welton Sep 12 '21 at 01:54
  • 1
    I wrote example code below and tested it in my own env, and it works. =) – Chris Welton Sep 12 '21 at 01:56

2 Answers2

2

Capture the current value of i when declaring the lambda:

from tkinter import *

root = Tk()

room_type = ['kitchen', 'living_room', 'bedroom', 'bathroom', 'study', 'laundry', 'dining_room']


def new_room(r):
    print(r)


for i in range(len(room_type)):
    globals()[f'{room_type[i]}_add'] = Button(root, text='Add a ' + room_type[i],
                                              command=lambda pi=i: new_room(r=room_type[pi]))
    globals()[f'{room_type[i]}_add'].grid(row=1, column=i)

root.mainloop()
Chris Welton
  • 104
  • 8
0

The use of lamda is making another loop of function which stops at the end of the last items and thus for every loop it stays the last i. Try removing the lamda and check out.

from tkinter import *

root = Tk()

room_type = ['kitchen', 'living_room', 'bedroom', 'bathroom', 'study', 'laundry', 'dining_room']


def new_room(r):
    print(r)


for i in range(len(room_type)):
    globals()[f'{room_type[i]}_add'] = Button(root, text='Add a ' + room_type[i],
                                              command=new_room(r=room_type[i]))
    globals()[f'{room_type[i]}_add'].grid(row=1, column=i)

root.mainloop()
t.abraham
  • 108
  • 1
  • 9