python - 如何移动 Canvas 多边形?

我想在 python tkinter 中移动对象,特别是多边形。问题出在 is_click 函数中。我似乎无法弄清楚如何确定我是否单击了该对象。代码还没有 100% 完成,移动仍然需要完成,但我现在需要弄清楚这一点。我也有类似的类,您可以在其中移动圆和矩形,其中 is_click 函数正在运行,但由于多边形具有 3 到 4 个坐标,因此有点复杂。自己运行这些类,看看它们在做什么。

我的多边形代码:

import tkinter

class Polygon:

    def __init__(self, ax, ay, bx, by, cx, cy, dx=None, dy=None, color=None):
        self.ax = ax
        self.ay = ay
        self.bx = bx
        self.by = by
        self.cx = cx
        self.cy = cy
        self.dx = dx
        self.dy = dy
        self.color = color

    def is_click(self, event_x, event_y):
        pass

    def paint(self, g):
        self.g = g
        if self.dx is None:
            self.id = self.g.create_polygon(self.ax,self.ay,
                                            self.bx,self.by,
                                            self.cx,self.cy,
                                            fill=self.color)
        else:
            self.id = self.g.create_polygon(self.ax,self.ay,
                                            self.bx,self.by,
                                            self.cx,self.cy,
                                            self.dx,self.dy,
                                            fill=self.color)

    def move(self, d_ax=0, d_ay=0, d_bx=0, d_by=0, d_cx=0, d_cy=0, d_dx=None, d_dy=None):
        if d_dx is None:
            self.ax += d_ax
            self.ay += d_ay
            self.bx += d_bx
            self.by += d_by
            self.cx += d_cx
            self.cy += d_cy
            self.g.move(self.id, d_ax, d_ay, d_bx, d_by, d_cx, d_cy)
        else:
            self.ax += d_ax
            self.ay += d_ay
            self.bx += d_bx
            self.by += d_by
            self.cx += d_cx
            self.cy += d_cy
            self.dx += d_dx
            self.dy += d_dy
            self.g.move(self.id, d_ax, d_ay, d_bx, d_by, d_cx, d_cy, d_dx, d_dy)


class Tangram:

    def __init__(self):
        self.array = []
        self.g = tkinter.Canvas(width=800,height=800)
        self.g.pack()

        #all objects
        self.add(Polygon(500,300,625,175,750,300, color='SeaGreen'))
        self.add(Polygon(750,50,625,175,750,300, color='Tomato'))
        self.add(Polygon(500,175,562.6,237.5,500,300, color='SteelBlue'))
        self.add(Polygon(500,175,562.5,237.5,625,175,562.5,112.5, color='FireBrick'))
        self.add(Polygon(562.5,112.5,625,175,687.5,112.5, color='DarkMagenta'))
        self.add(Polygon(500,50,500,175,625,50, color='Gold'))
        self.add(Polygon(562.5,112.5,687.5,112.5,750,50,625,50, color='DarkTurquoise'))
        #end of all objects

        self.g.bind('<Button-1>', self.event_move_start)

    def add(self, Object):
        self.array.append(Object)
        Object.paint(self.g)

    def event_move_start(self, event):
        ix = len(self.array) - 1
        while ix >= 0 and not self.array[ix].is_click(event.x, event.y):
            ix -= 1
        if ix < 0:
            self.Object = None
            return
        self.Object = self.array[ix]
        self.ex, self.ey = event.x, event.y
        self.g.bind('<B1-Motion>', self.event_move)
        self.g.bind('<ButtonRelease-1>', self.event_release)

    def event_move(self):
        pass

    def event_release(self):
        pass

Tangram()

以及圆形和矩形移动的代码:

import tkinter, random

class Circle:
    def __init__(self, x, y, r, color='red'):
        self.x = x
        self.y = y
        self.r = r
        self.color = color

    def is_click(self, x, y):
        return (self.x-x)**2+(self.y-y)**2 < self.r**2

    def paint(self, g):
        self.g = g
        self.id = self.g.create_oval(self.x-self.r,self.y-self.r,
                      self.x+self.r,self.y+self.r,
                      fill=self.color)

    def move(self, dx=0, dy=0):
        self.g.delete(self.id)
        self.x += dx
        self.y += dy
        self.paint(self.g)

class Rectangle:
    def __init__(self, x, y, width, height, color='red'):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color

    def is_click(self, x, y):
        return self.x<=x<self.x+self.width and self.y<=y<self.y+self.height

    def paint(self, g):
        self.g = g
        self.id = self.g.create_rectangle(self.x,self.y,
                      self.x+self.width,self.y+self.height,
                      fill=self.color)

    def move(self, dx=0, dy=0):
        self.x += dx
        self.y += dy
        self.g.move(self.id, dx, dy)

class Program:
    def __init__(self):
        self.array = []
        self.g = tkinter.Canvas(bg='white', width=400, height=400)
        self.g.pack()
        for i in range(20):
            if random.randrange(2):
                self.add(Circle(random.randint(50, 350),random.randint(50, 350), 20, 'blue'))
            else:
                self.add(Rectangle(random.randint(50, 350),random.randint(50, 350), 40, 30))
        self.g.bind('<Button-1>', self.event_move_start)

    def add(self, Object):
        self.array.append(Object)
        Object.paint(self.g)

    def event_move_start(self, e):
        ix = len(self.array)-1
        while ix >= 0 and not self.array[ix].is_click(e.x, e.y):
            ix -= 1
        if ix < 0:
            self.Object = None
            return
        self.Object = self.array[ix]
        self.ex, self.ey = e.x, e.y
        self.g.bind('<B1-Motion>', self.event_move)
        self.g.bind('<ButtonRelease-1>', self.event_release)

    def event_move(self, e):
        self.Object.move(e.x-self.ex, e.y-self.ey)
        self.ex, self.ey = e.x, e.y

    def event_release(self, e):
        self.g.unbind('<B1-Motion>')
        self.g.unbind('<ButtonRelease-1>')
        self.Object = None

Program()

最佳答案

这不是您问题的完整答案,但评论太长了。我会集中考虑的一种方法是更改​​/修改您的代码,以便它使用 find_closes 方法。使用此方法,您可以非常轻松地确定单击了哪个小部件(即多边形)。作为概念的快速证明,您可以在 Tangram 和 ploygon 类中进行以下更改:

def event_move_start(self, event):
  ix = len(self.array) - 1
  while ix >= 0 and not self.array[ix].is_click(event, self.g, event.x, event.y): # add event and canvas to argumetns

在多边形中:

def is_click(self, event, g, event_x, event_y):
    widget_id = event.widget.find_closest(event.x, event.y)
    print(widget_id)
    g.move(widget_id, 1, 1) # just dummy move for a clicked widget
    pass

这将打印点击的小部件/多边形的 ID 并稍微移动点击的多边形。这可用于选择单击了哪个对象,有了这个 id 对象,您就可以进行移动或其他操作。

附注我用来测试它的完整代码是 here .

希望这对您有所帮助。

https://stackoverflow.com/questions/27735649/

相关文章:

c# - 在linq中动态选择一个属性

javascript - 如何更改 D3 中的缩放速度

ruby-on-rails - Mongoid 批量收集插入 : how to get the id

inno-setup - 如何在 InnoSetup 中更改 {app} 变量

python - pymssql : Inserting mutliple values into

django - 如何从 Django 中的信号获取返回响应

bash - 如何获取wget下载的文件的文件名

javascript - 单击播放音频时出现不必要的延迟

ruby-on-rails - 康康舞能力 : allow site admin with roli

visual-studio-2013 - 即使通过 NuGet 安装,SpecFlow 也找不到包