如何移动Canvas多边形?

时间:2015-01-01 23:22:41

标签: python tkinter

我想在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()

和Circle和Rectangle移动的代码:

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()

1 个答案:

答案 0 :(得分:0)

这不是你问题的完整答案,但是评论的时间太长了。我会集中考虑的一种方法是更改​​/修改代码,以便它使用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对象,您可以移动或其他任何。

P.S。我用来测试它的完整代码是here

希望这有帮助。