Problem is that tkinter can bind many functions to event and there is already binded default function which changed relief when you click button. You can use return "break" in your function to inform tkinter that you processed this event and it will skip other functions.
Or you could use standard command= to assing function and then it will skip other function.
import tkinter as tk # PEP8: `import *` is not preferred
# --- functions ---
def selected1(event):
event.widget.config(relief='sunken' if event.widget.cget('relief') == 'raised' else 'raised')
return "break"
def selected2():
B2.config(relief='sunken' if B2.cget("relief") == 'raised' else 'raised')
# --- main ---
root = tk.Tk()
B1 = tk.Button(root, text='BUTTON1', relief='raised')
B1.bind("<Button>", selected1)
B1.grid(row=1, column=2, sticky='news')
B2 = tk.Button(root, text='BUTTON2', relief='raised', command=selected2)
B2.grid(row=2, column=2, sticky='news')
root.mainloop()
The same using for-loop and lambda.
Normally it use only reference to button which valeu is changed in loop so finally all functions use reference to the same value - which is last value assigned in loop.
Using lambda arg=button it create new variable in every loop and copy value from button to arg so every widget use different arg with differen value.
import tkinter as tk # PEP8: `import *` is not preferred
# --- functions ---
def selected(widget):
widget.config(relief='sunken' if widget.cget('relief') == 'raised' else 'raised')
# --- main ---
root = tk.Tk()
for x in range(1, 6):
button = tk.Button(root, text=f'LOOP BUTTON {x}', relief='raised')
#button.config(command=lambda arg=button:selected3(arg))
button['command'] = lambda arg=button:selected(arg)
button.grid(row=x, column=2, sticky='news')
root.mainloop()
As @acw1668 mentioned in comment you can also uses Checkbutton(..., indicator=False) to get the same effect without extra function
import tkinter as tk # PEP8: `import *` is not preferred
# --- main ---
root = tk.Tk()
for x in range(1, 6):
button = tk.Checkbutton(root, text=f'LOOP BUTTON {x}', indicator=False, padx=10, pady=5)
button.grid(row=x, column=2, sticky='news')
root.mainloop()
print()to check what you getevent.widget.cget("relief")when you click it. Second: create minimal working code with your problem which we can test.return 'break'inselect()function.Checkbuttonwithindicator=Falsewhich has the same effect.return "break"just skip the default event handlers. Once again, I prefer usingCheckbuttonwithindicator=False.arg=- you can't put it directly inselected()-button['command'] = lambda arg=button:selected(arg)All problem is that it doesn't copy value frombuttontoselected(button)but only reference to variablebuttonwhich is changed in loop so finally allselecteduse reference to the same value - last value infor-loop. Usingarg=buttonit creates new variable in every loop and it copies value frombuttontoarg- so everyselected()use differenargwith different value.