0

Why my Tkinter bind buttons work incorrectly? When I go on the start button with the mouse, about button will change! show image

This is my code:

import tkinter as tk


class Panel(tk.Tk):

    def __init__(self):
        super().__init__()

        # window config
        self.title('test')
        self.geometry('300x300')
        self.configure(bg='#2b2e37')
 
   
    def btns(self, x, y, text, bg, fg):
        def on_enter(ctx):
            self.btn['background'] = fg
            self.btn['foreground'] = bg
        def on_leave(ctx):
            self.btn['background'] = bg
            self.btn['foreground'] = fg

        
        self.btn = tk.Button(self, text=text, bg=bg, fg=fg, activebackground=fg, activeforeground=bg, border=0, width=42, height=2)
        self.btn.bind('<Enter>', on_enter)
        self.btn.bind('<Leave>', on_leave)
        self.btn.place(x=x, y=y)
        

if __name__ == '__main__':
    window = Panel()
    window.btns(0, 190, 'S T A R T', '#2b2e37', '#56fc03')
    window.btns(0, 230, 'A B O U T', '#2b2e37', '#f5ec42')
    window.mainloop()

I think it's for my oop code, I wrote this simply and worked correctly. Sorry for my bad English

erfannjz
  • 3
  • 2
  • Please ensure you've posted all of your code. It looks like you're missing a line containing `class Panel` and perhaps some others? – Luke Woodward Feb 19 '22 at 21:16
  • 1
    You create exactly one instance of `Panel`, and that instance has exactly one attribute named `btn`. You're storing both Buttons in that attribute; the second one overwrites the first. – jasonharper Feb 19 '22 at 23:40
  • Tnx for your help but is any way to write it shorter? look at my answer @jasonharper – erfannjz Feb 20 '22 at 07:09

2 Answers2

1

The button on which the event occurs is passed to the event handlers in the ctx parameter in the widget attribute, so you can use that instead of self.btn:

    def btns(self, x, y, text, bg, fg):
        def on_enter(ctx):
            ctx.widget['background'] = fg
            ctx.widget['foreground'] = bg
        def on_leave(ctx):
            ctx.widget['background'] = bg
            ctx.widget['foreground'] = fg

The problem with using self.btn in place of ctx.widget in these event handlers is that the second time you call btns, self.btn is replaced with the second button, so the event handlers you added to the first button end up making changes to the second button.

Luke Woodward
  • 63,336
  • 16
  • 89
  • 104
0

I fixed my code by writing separately for each button.

New code:

    def btns(self):
        def on_enter1(ctx):
            self.btn1['background'] = '#56fc03'
            self.btn1['foreground'] = '#2b2e37'
        def on_leave1(ctx):
            self.btn1['background'] = '#2b2e37'
            self.btn1['foreground'] = '#56fc03'
        def on_enter2(ctx):
            self.btn2['background'] = '#f5ec42'
            self.btn2['foreground'] = '#2b2e37'
        def on_leave2(ctx):
            self.btn2['background'] = '#2b2e37'
            self.btn2['foreground'] = '#f5ec42'

        
        self.btn1 = tk.Button(self, text='S T A R T', bg='#2b2e37', fg='#56fc03', activebackground='#56fc03', activeforeground='#2b2e37', border=0, width=42, height=2)
        self.btn2 = tk.Button(self, text='A B O U T', bg='#2b2e37', fg='#f5ec42', activebackground='#f5ec42', activeforeground='#2b2e37', border=0, width=42, height=2)
        self.btn1.bind('<Enter>', on_enter1)
        self.btn1.bind('<Leave>', on_leave1)
        self.btn2.bind('<Enter>', on_enter2)
        self.btn2.bind('<Leave>', on_leave2)
        self.btn1.place(x=0, y=190)
        self.btn2.place(x=0, y=230)

if __name__ == '__main__':
    window = Panel()
    window.label()
    window.btns()
    window.mainloop()
erfannjz
  • 3
  • 2