How can I pass the TKinter button/label that triggered a bind to a function which that bind calls?

I hope someone can help with this. I’m new to coding and wanted to try doing some GUI stuff in Python with TKinter. In one of my projects, I want any button that the mouse hovers over to change it’s background color. However I don’t want to define a function for every single button. Here is an example:

from tkinter import *

root = Tk()
root.title("Example")
root.configure(bg="black")

def on_enter(e, button):
    #button = Button that triggered the bind
    button.configure(bg="red")

def on_leave(e, button):
    #button = Button that triggered the bind
    button.configure(bg="black")

button1 = Button(root, text="Button1", width=10, height=10, bg="black", fg="white")
button2 = Button(root, text="Button2", width=10, height=10, bg="black", fg="white")
button3 = Button(root, text="Button3", width=10, height=10, bg="black", fg="white")
button4 = Button(root, text="Button4", width=10, height=10, bg="black", fg="white")

button1.grid(column=0, row=0)
button2.grid(column=0, row=1)
button3.grid(column=1, row=0)
button4.grid(column=1, row=1)

#How can I give the button that triggered the bind as an argument to the functions on_enter/on_leave?
root.bind_all("<Enter>", lambda e, button: on_enter(e, button))
root.bind_all("<Leave>", lambda e, button: on_leave(e, button))

#root.bind_class("Button", "<Enter>", lambda e, button: on_enter(e, button))
#root.bind_class("Button", "<Leave>", lambda e, button: on_leave(e, button))


root.mainloop()

Now of course I could go and make a function for every button to change it’s background color when the bind for that specific button calls that function. But is there a way to pass the button that triggered the bind to the function that the bind calls ?

My example works, if I explicitly put the button I want to change in the bind like this:

root.bind_all("<Enter>", lambda e, button = button1: on_enter(e, button))
root.bind_all("<Leave>", lambda e, button = button1: on_leave(e, button))

But I thought there must be a more elegant way to fix this other than make a bind/function for every single button which gets really annyoing when I have a program with more than only 4 buttons.

I hope someone has any advice 🙂

Answer

When you bind an event to a function, that function will be called with an object representing the event. This object has an attribute widget which is the widget that received the event. You don’t need to do anything else to get the widget.

def on_enter(event):
    event.widget.configure(bg="red")

root.bind_all("<Enter>", on_enter)