1

Whenever I dynamically create buttons in tkinter through a loop, to call a function with a value assigned to them through the loop, like so:

from tkinter import *
root=Tk()
def add(text):
    print(text)
for i in ('a', 'b', 'c'):
    Button(root, text=i, command=lambda:add(i)).pack()
mainloop()

I always have the problem that the function is called with the last value in the loop, whatever button I press. In this case, it simply prints c whatever button I press. I do not know if this is a problem with lambda or tkinter, or simply my programming, but I would like to know how to fix it.

I have tried using copy.copy, copy.deepcopy (on the lambda function and the string), and [:] and str (on the string).

Artemis
  • 2,553
  • 7
  • 21
  • 36
  • @Aran-Fey While the linked question's answer will provide me with a solution, it does not answer my question as it **defines functions**, and does not use `lambda`. When I try `lambda:add(text=i)`, I have the same problem. – Artemis Jul 14 '18 at 19:00
  • I don't understand what the difference is. `lambda` is just a different way to define a function. (And if you read the answer(s) carefully, you'll find out that you need `lambda i=i:add(i)` instead of `lambda:add(text=i)`.) – Aran-Fey Jul 14 '18 at 19:02
  • @Aran-Fey `lambda i` takes `i` as a parameter, my function should not, it should just use `i` in the function. – Artemis Jul 14 '18 at 19:07
  • If the optional parameter is really a problem, you can use the `make_f` solution proposed in the very same answer. – Aran-Fey Jul 14 '18 at 19:08
  • @Aran-Fey I have Realised what you meant earlier now. Thanks for patence and help. I don't know how to retract my reopen vote but I would. – Artemis Jul 14 '18 at 19:11

1 Answers1

4

There is a common trick:

for i in ...:
    def command(i=i):
        add(i)
    Button(..., command=command)

It looks a little ugly, but it captures the current value of i in the default argument values. There are other ways to solve this problem but this solution is fairly succinct.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415