使用 tkinter 跟踪 canvas 上每个多边形的每个点

Keeping track of each point of each polygon on a canvas with tkinter

我正在 UI 使用 tkinter 在 Python 中制作和 UI 七巧板(具有不同多边形的拼图),我想跟踪每个多边形的每个点的坐标他们在我的 canvas.

周围移动

为此,我创建了这个 class:

class Polygon:
    def __init__(self, coords, color, canvas):
        self.coords = coords
        self.color = color
        self.move = False

        canvas.bind('<Button-1>', self.start_movement)
        canvas.bind('<Motion>', self.movement)
        canvas.bind('<ButtonRelease-1>', self.stopMovement)
        canvas.bind('<Button-3>', self.rotate)

        canvas.create_polygon(self.coords, fill=self.color)

每个多边形都是这样创建的:

medium_triangle = Polygon((0,0, 100*math.sqrt(2),0, 0,100*math.sqrt(2)),
                          'red', drawing_place)
small_triangle_1 = Polygon((0,0 ,100,0, 0,100), 'purple', drawing_place)
[...]
big_triangle_2 = Polygon((0,0, 200,0, 0,200), 'green', drawing_place)

我的主要问题是,看起来我只能修改最后创建的 Polygoncoords 属性。 我用鼠标拖动 canvas 上的棋子,然后使用这些方法让我的多边形移动:

def start_movement(self, event):
    self.move = True

    # Translate mouse coordinates to canvas coordinate
    self.initi_x = drawing_place.canvasx(event.x)
    self.initi_y = drawing_place.canvasy(event.y)

    self.movingimage = drawing_place.find_closest(self.initi_x, self.initi_y,
                                                  halo=1)  # get canvas object
                                                           # ID of where mouse
                                                           # pointer is.

def movement(self, event):
    if self.move:

        end_x = drawing_place.canvasx(event.x)  # Translate mouse x screen
                                                # coordinate to canvas coordinate.
        end_y = drawing_place.canvasy(event.y)  # Translate mouse y screen
                                                # coordinate to canvas coordinate.

        deltax = end_x - self.initi_x  # Find the difference
        deltay = end_y - self.initi_y  # Find the difference

        self.newPosition(deltax, deltay)

        self.initi_x = end_x  # Update previous current with new location
        self.initi_y = end_y
        drawing_place.move(self.movingimage, deltax, deltay)  # Move object

def stopMovement(self, event):
    self.move = False
    affichage(self)

我设法将位移添加到我的初始坐标中,这要归功于我的 new_position 方法:

def newPosition(self, deltax, deltay):
    coord = self.coords  # Retrieve object points coordinates
    old_coord = list(coord)  # Tuple to List
    c = []  # New coords
    i = 0  # Cursor on old_coord
    for coordinates in old_coord:

        # check if index of coordinates in range of i and len(old_coord)
        # in old_coord is pair (x coord).
        if (old_coord.index(coordinates, i, len(old_coord)) % 2) == 0:
            c.append(coordinates + deltax)
        else:  # index's impair => y-coord
            c.append(coordinates + deltay)
        i += 1

    coord2 = tuple(c)  # List to Tuple
    self.set_coords(coord2)

 def set_coords(self, coords):
    self.coords = coords

但正如您在我的控制台中看到的那样

just after medium_triangle declaration:
(0, 0, 141.4213562373095, 0, 0, 141.4213562373095)
(0, 0, 200, 0, 0, 200)
(0, 0, 200, 0, 0, 200)
(0, 0, 200, 0, 0, 200)
(0, 0, 200, 0, 0, 200)
(297.0, 61.0, 497.0, 61.0, 297.0, 261.0)
(551.0, 166.0, 751.0, 166.0, 551.0, 366.0)
(951.0, 250.0, 1151.0, 250.0, 951.0, 450.0)

在声明我的多边形时,我似乎可以用 medium_triangle.coords 打印它们的坐标,但是之后,当我点击我的 canvas 时,它直接显示最后一个的坐标宣布。当我在 canvas 上移动另一块时,它只会添加到相同的 Polygon.

我对 classes 和方法等不太满意,但我认为我明白我的每个多边形都是我的 class 的不同实例,但尽管如此,看起来我可以仅访问 Polygon.

的一个实例

我希望我的问题很清楚,我真的创建了不同的多边形吗?如果是,为什么我不能单独修改它们?

canvas.bind('<Button-1>', self.start_movement)
canvas.bind('<Motion>', self.movement)
canvas.bind('<ButtonRelease-1>', self.stopMovement)
canvas.bind('<Button-3>', self.rotate)

您的 canvas(类型 Canvas,或者我假设)只能绑定到每个键的一个操作。试试这个代码:

canvas.bind('<Button-1>', self.start_movement)
canvas.bind('<Button-1>', lambda e: print("ok"))

...您会发现它不再调用 start_movement(),因为将调用 lambda。 在这里,唯一绑定到 canvas 的函数是您上次调用的函数:因此在您创建的最后一个 Polygon 的初始化中的函数。通过绑定新方法,您删除了以前对相同键的绑定。

您不应在 Polygon class 中使用 canvas.bind(...)。使用 canvas.tag_bind(...) 代替:

class Polygon:
    def __init__(self, coords, color, canvas):
        self.coords = coords
        self.color = color
        self.move = False
        self.canvas = canvas

        self.id = canvas.create_polygon(self.coords, fill=self.color)

        canvas.tag_bind(self.id, '<Button-1>', self.start_movement)
        canvas.tag_bind(self.id, '<Motion>', self.movement)
        canvas.tag_bind(self.id, '<ButtonRelease-1>', self.stopMovement)
        canvas.tag_bind(self.id, '<Button-3>', self.rotate)

请注意,我已将传递的 canvas 保存到实例变量 self.canvas 中。您应该在其他 class 方法中将所有 drawing_place 替换为 self.canvas

此外,您不需要在 start_movement() 中调用以下行:

    self.movingimage = drawing_place.find_closest(self.initi_x, self.initi_y,
                                                  halo=1)  # get canvas object
                                                           # ID of where mouse
                                                           # pointer is.

因为self.id可以用来代替movement()里面find_closest()的结果:

    def movement(self, event):
        if self.move:

            end_x = self.canvas.canvasx(event.x)  # Translate mouse x screen
                                                    # coordinate to canvas coordinate.
            end_y = self.canvas.canvasy(event.y)  # Translate mouse y screen
                                                    # coordinate to canvas coordinate.

            deltax = end_x - self.initi_x  # Find the difference
            deltay = end_y - self.initi_y  # Find the difference

            self.newPosition(deltax, deltay)

            self.initi_x = end_x  # Update previous current with new location
            self.initi_y = end_y
            self.canvas.move(self.id, deltax, deltay)  # Move object