4

I don't get how to reference the button being clicked in tkinter.

My code:

for file in files: 
     btn = Button(root, text=file).pack()

Now e.g. 50 buttons are generated from files which is the source.
However when I click any button, only the LAST button is being referenced, but not the button I really want to use/click.

In JavaScript we use this to reference the object we really clicked, however I couldn't find any solution in Python for this.

Lafexlos
  • 7,618
  • 5
  • 38
  • 53
cytzix
  • 95
  • 1
  • 2
  • 8
  • 1
    @EthanField Please don't add code to the question. There is no indication that OP uses [tag:python-3.x] or a list for `files`. If you are not sure, use comments to get clarification. – Lafexlos Aug 17 '17 at 11:14
  • The OP had already provided code, I made it runnable, I don't see any concerns with that, other than the difference between "Tkinter" and "tkinter" the code would run in 2.x or 3.x. Additionally, the OP declared `for file in files:` meaning that files is a `list`, so whilst the OP hadn't provided us with any data for `files` I added a for loop to populate it with the 50 buttons that the OP stated the script should add. I also don't agree with the classification of this question as a duplicate, the two questions are clearly different – Ethan Field Aug 17 '17 at 11:29
  • @EthanField _OP declared for file in files: meaning that files is a list_ Umm.. No. `files` can be any iterable(i.e generator, amp object, zip object etc.) and we have no idea how it is generated. About duplicate.. Linked question _exactly_ does what OP explains. How it is not duplicate? – Lafexlos Aug 17 '17 at 11:50

1 Answers1

7

This can be done with something like the below:

from tkinter import *

root = Tk()

files = [] #creates list to replace your actual inputs for troubleshooting purposes
btn = [] #creates list to store the buttons ins

for i in range(50): #this just popultes a list as a replacement for your actual inputs for troubleshooting purposes
    files.append("Button"+str(i))

for i in range(len(files)): #this says for *counter* in *however many elements there are in the list files*
    #the below line creates a button and stores it in an array we can call later, it will print the value of it's own text by referencing itself from the list that the buttons are stored in
    btn.append(Button(root, text=files[i], command=lambda c=i: print(btn[c].cget("text"))))
    btn[i].pack() #this packs the buttons

root.mainloop()

So what this does is create a list of buttons, each button has a command assigned to it which is lambda c=i: print(btn[c].cget("text").

Let's break this down.

lambda is used so that the code following isn't executed until the command is called.

We declare c=i so that the value i which is the position of the element in the list is stored in a temporary and disposable variable c, if we don't do this then the button will always reference the last button in the list as that is what i corresponds to on the last run of the list.

.cget("text") is the command used to get the attribute text from a specific tkinter element.

The combination of the above will produce the result you want, where each button will print it's own name after being pressed, you can use similar logic to apply it to call whatever attribute or event you need.

Ethan Field
  • 4,646
  • 3
  • 22
  • 43