Reputation: 191
I want to link my buttons with labels, however I am not allowed to explicitly declare them as variables because I will use loop for it (e.g. number of button-label pair will depend on user input).
for i in range(desired_number):
button = tk.Button(self.mainframe)
button.grid(row = i, column = 0)
label = tk.Label(self.mainframe)
label.grid(row = i, column = 1)
button.config(command = lambda: self.changetext(label))
@staticmethod
def changetext(label):
label.config(text="button on my left has been pressed")
this however doesn't work. It seems that I can't just pass the object, but also have to pass the explicit name for it. Any idea on tackling this?
Upvotes: 0
Views: 194
Reputation: 5541
If you are using python 3.8+ you can use a walrus (:=
) and accomplish what you want on 2 lines. It doesn't matter that the Label
is being added to the grid
before the Button
. Their grid
positions were defined and those are the positions they will reside in.
Using names like desired_count
and change_label
is too generic. I changed those names to better reflect what they refer to.
import tkinter as tk
def indicate_button(label):
label['text'] = 'corresponding button pressed'
root = tk.Tk()
combo_count = 5
for i in range(combo_count):
(lbl := tk.Label(root, width=25)).grid(row=i, column=1)
tk.Button(root, text=f"Button {i}", command=lambda L=lbl: indicate_button(L)).grid(row=i, column=0)
root.mainloop()
Another way to do this would be to store the Label
in a list. I realize this answer was already given, but their version is messy, incomplete and has errors. I also extended the example to show how this could be useful.
import tkinter as tk
root = tk.Tk()
combo_count = 5
labels = [None]*combo_count
def indicate_button(i):
if i < len(labels) and labels[i]:
for n, lbl in enumerate(labels):
#assign target label and clear the others
lbl['text'] = 'corresponding button pressed' if n == i else ''
else:
#do something about an out of range or empty index
pass
for i in range(combo_count):
labels[i] = tk.Label(root, width=25)
labels[i].grid(row=i, column=1)
tk.Button(root, text=f'Button {i}', command=lambda i=i: indicate_button(i)).grid(row=i, column=0)
root.mainloop()
Upvotes: 0
Reputation: 11342
For dynamically created widgets, you can store them in a array for later access. In this case, you can pass the label index to the button handler.
lstbtn = []
lstlbl = []
for i in range(desired_number):
button = tk.Button(self.mainframe)
button.grid(row = i, column = 0)
lstbtn.append(button) # save for later
label = tk.Label(self.mainframe)
label.grid(row = i, column = 1)
lstlbl.append(label) # save for later
button.config(command = lambda: self.changetext(i)) # pass label index
@staticmethod
def changetext(idx): # label index
lstlbl[idx].config(text="button on my left has been pressed")
Upvotes: 0
Reputation: 7006
Try adding a parameter to your lambda. This way it should use each button seperately rather than just the last button/label defined. Simple executable example below
import tkinter as tk
def changetext(label):
label.config(text="button on my left has been pressed")
root = tk.Tk()
desired_number = 5
for i in range(desired_number):
button = tk.Button(root,text=f"Button {i}")
button.grid(row = i, column = 0)
label = tk.Label(root)
label.grid(row = i, column = 1)
button.config(command = lambda x=label: changetext(x))
root.mainloop()
Upvotes: 1