Метод класса срабатывает только на последнем экземпляре python

Рейтинг: 1Ответов: 1Опубликовано: 17.08.2023

У меня вопрос в следующем:
При нажатии на левую кнопку мыши должно фиксироваться попадание, но почему то оно фиксируется только по одному кубику.
Код прилагаю.

from tkinter import *
import random

class Rectangle:
    def __init__(self, canvas, coord, fill, outline=None):
        self.x = random.randint(-5, 5)
        self.y = random.randint(-5, 5)
        self.canvas = canvas
        self.outline = outline if outline is not None else fill
        self.fill = fill
        self.canvas_id = self.canvas.create_rectangle(coord, outline=self.outline, fill=self.fill)
        
        self.canvas.bind('<Button-1>', self.click)

    def draw(self):
        if (self.canvas.coords(self.canvas_id)[0] < 1 or self.canvas.coords(self.canvas_id)[2] > 700):
            self.x = self.x * (-1)
        elif (self.canvas.coords(self.canvas_id)[1] < 1 or self.canvas.coords(self.canvas_id)[3] > 400):
            self.y = self.y * (-1)
        self.canvas.move(self.canvas_id, self.x, self.y)
        self.canvas.after(35, self.draw)
        

    def click(self, event):
        x = event.x
        y = event.y
        print(self.canvas_id)
        if (x < self.canvas.coords(self.canvas_id)[2] and x > self.canvas.coords(self.canvas_id)[0]) and (
                y < self.canvas.coords(self.canvas_id)[3] and y > self.canvas.coords(self.canvas_id)[1]):
            print('Target')
            #self.canvas.delete(self.canvas_id)



root = Tk()
root.geometry('800x500')
root.title('Курсовая работа')

c = Canvas(width=700, height=400, bg='black')
c.place(x=50, y=10)

rectangle = [Rectangle(c, (10, 20, 40, 50), fill='red') for i in range(8)]
for rec in rectangle:
    rec.draw()

# Кнопки запуска, остановки и выхода из программы
vars = IntVar()
vars.set(0)
r1 = Radiobutton(text='СТАРТ', indicatoron=0, variable=vars, value=1, font='Times 15', bg='green')
r2 = Radiobutton(text='СТОП', indicatoron=0, variable=vars, value=0, font='Times 15',  bg='yellow')
r1.place(x=50, y=430)
r2.place(x=150, y=430)


root.mainloop()

Ответы

▲ 1Принят

Вы в «цикле» создали 8 объектов - rectangle[0], ..., rectangle[7].
При создании каждого из них выполняется (в методе __init__()) команда

self.canvas.bind('<Button-1>', self.click)

self.canvas для каждого из них тот же самый объект — c. Но self.click нет, потому что этот метод специфичен для каждого объекта — он тестирует совпадение клика мышей только для этого объекта.

Значит, после создания нового и нового объекта вы всякий раз переписываете связь между кликом мышей и функцией, которую он должен выполнить, а в конце клик будет связанный только с процедурой для последнего объекта.

self.click в методе .bind() будет просто rectangle[7].click!


Исправление:

Удалите эту команду из метода __init__() и тем самым и определение метода click() из определения класса. Код метода click() используйте в функции клик, т.е. вне определения класса, где-то после создания объекта c (типа Canvas) и списка объектов rectangle:

def click(event):
    x = event.x
    y = event.y
    for rec in rectangle:
        if (x < rec.canvas.coords(rec.canvas_id)[2] and x > rec.canvas.coords(rec.canvas_id)[0]) and (
                y < rec.canvas.coords(rec.canvas_id)[3] and y > rec.canvas.coords(rec.canvas_id)[1]):
            print('Target')

Затем свяжите клик мышей с этой функцией:

c.bind('<Button-1>', click) 

Примечание:

Я употребил ваш код из метода .click() класса Rectangle, чтобы вы сразу увидели похожесть. Но как вы сам наверно понимаете, он не самый красивый.

Я надеюсь, что и вам будет лучше нравиться этот:

def click(event):
    x = event.x
    y = event.y
    for rec in rectangle:
        x1, y1, x2, y2 = rec.canvas.coords(rec.canvas_id)
        if (x1 < x < x2) and (y1 < y < y2):
            print('Target')