Ansh Gupta
Ansh Gupta

Reputation: 47

Variable is Changing without Me Touching it

I'm trying to make a memory game, and I have a class called 'Button'.

tk = Tk()
tk.title('Memory Game')
tk.wm_attributes('-topmost', 1)
tk.resizable(0, 0)
canvas = Canvas(tk, width=400, height=600, bg='white', bd=0, 
highlightthickness=0)
canvas.pack()
tk.update()
class Button:
    def __init__(self, pos):
        self.pos = pos
        self.open = False
        self.canvas = canvas
        self.id = canvas.create_rectangle(pos[0], pos[1], pos[0]+100, pos[1]+100, fill='blue')
        self.canvas.bind_all("<Button-1>", self.action)
        print(self.pos)
        #The positions are what they're supposed to be as of now.
    def action(self, event):
        print(self.pos)
        #If you click on the screen, then the console prints out [300, 400] no matter what the actual position is.
        print(event.x, event.y) #Prints out coords of where the mouse clicked
        if event.x >= self.pos[0] and event.x <= self.pos[0] + 100:
            if event.y >= self.pos[1] and event.y <= self.pos[1]+100:
                self.canvas.coords(self.id, 1000, 1000, 1100, 1100)
                #Makes Button Disappear from Tkinter Window
button_pos = [[0, 100], [0, 200], [0, 300], [0, 400], [100, 100], [100, 200], [100, 300], [100, 400], [200, 100], [200, 200], [200, 300], [200, 400], [300, 100], [300, 200], [300, 300], [300, 400]]
//coordinates for the buttons
buttons = []
for x in range(16):
    buttons.append(Button(button_pos[x]))

If you run this and click on the screen, you will see that the position of the buttons is seemingly always [300,400], no matter what. Why does this happen? None of the buttons actually disappear except for the bottom right one.

Upvotes: 0

Views: 74

Answers (1)

abarnert
abarnert

Reputation: 365707

The problem is here:

self.canvas.bind_all("<Button-1>", self.action)

Each button tries to take over all Button-1 events for the entire canvas—in fact, because you're using bind_all, for all widgets anywhere in the app. So, each one steals the binding from the one before, and at the end, the last button gets all clicks.

What you want to do is have the canvas bind the button, then hit-test the click, and then pass it to the rectangle manually. For example, after all of your existing code (but before wherever you start the main loop), add this:

def action(event):
    item, = canvas.find_closest(event.x, event.y)
    buttons[item-1].action(event)
canvas.bind("<Button-1>", action)

And then remove the self.canvas.bind_all line. Now, the canvas gets its own clicks, finds the closest shape to the click (which will be a one-based index to your rectangles in the order of creation), and dispatches the event manually.

Upvotes: 1

Related Questions