Search code examples
python-3.xtkinterttk

Hover not working correctly on dynamic buttons in Tkinter


I am dynamically generating buttons in a tkinter GUI. I want those buttons to change their image upon hover. If I try to do it without passing the button as a parameter, I get an error 'AttributeError: 'Event' object has no attribute 'config'. If I try to pass 'link_file' as a parameter to 'link_button_hover' & 'link_button_mouseoff', when the button gets added it immediately runs hover and mouseoff functions then sits on the mouseoff image.

def link_button_hover(e):
    e.config(image=vid_link_hover_icon)

def link_button_mouseoff(e):
    e.config(image=vid_unlinked_icon)

def create_button()
    link_file = ttk.Button(new_spot_frame, text="...")
    link_file.grid(row=1,column=0)
    link_file.config(command=lambda button=link_file: open_file_dialog(button),image=vid_unlinked_icon)
    link_file.bind('<Enter>', link_button_hover)
    link_file.bind('<Leave>', link_button_mouseoff)

or if I try the version where I pass buttons as parameter:

link_file.bind('<Enter>', link_button_hover(link_file))
link_file.bind('<Leave>', link_button_mouseoff(link_file))

Solution

  • Event is an object with a number of attributes describing the event, but you are trying to configure it which is why you get the error. What you need is to use event.widget to properly retrieve the widget object:

    def link_button_hover(e):
        e.widget.config(image=vid_link_hover_icon)
    
    def link_button_mouseoff(e):
        e.widget.config(image=vid_unlinked_icon)
    

    Or if you prefer to pass the widget as an arg in your binding, use lambda:

    link_file.bind('<Enter>', lambda e: link_button_hover(link_file))
    link_file.bind('<Leave>', lambda e: link_button_mouseoff(link_file))