1
votes

I'm working on some code to move a shape drawn on a canvas. It's a vector drawing program overall so I need to be able to move one shape, and then another.

So far I have code that works for moving one shape, but when I then try to move another shape that is on the screen afterwards, the shape jumps before I can click it. I think what is happening is that the code for moving the shape is being activated without a click, and so the coordinates in the code aren't being reset, causing the shape to jump (the code I have should get the coordinates of the second shape when it's clicked, I hope)

I tried looking online for any reason why it's working without a click, but didn't find anything. I also tried unbinding the tags that move the shape after the first shape was placed, so that they wouldn't be bound until the second shape was clicked, but that didn't seem to work.

Can anyone explain what's happening here?

#code for a two shapes
circle = Main_Window.create_image(500,400, image = CircleIm, tags = "circle")
shape = circle
type1 = Move_Shape(shape)
Main_Window.tag_bind(circle, "<ButtonPress-3>", type1.moveShape(shape))

triangle= Main_Window.create_image(500,400, image = TriangleIm, tags = "triangle")
shape = triangle
type1 = Move_Shape(shape)
Main_Window.tag_bind(triangle, "<ButtonPress-3>", type1.moveShape(shape))


class Move_Shape:
    def __init__(self, shape):
        self.shape = shape
        return

def getShapeType(self, shape):
    global shapeType
    print(self.shape)
    shapeType = Main_Window.gettags(self.shape)  
    return shapeType

def moveShape(self, shape):
    #while left button is held down, we want it to move the tagged shape to     move to the position of the mouse
    global b1, currentX, currentY
    b1 = "down"
    newX, newY = None, None
    shapeType = self.getShapeType(shape)
    print(shapeType)

    Main_Window.addtag_withtag("move_shape", shapeType[0])
    #Bind move_shape to moving code
    print("new tags are", Main_Window.gettags(self.shape))
    Main_Window.tag_bind("move_shape","<Motion>", self.whileMoving)
    Main_Window.tag_bind("move_shape","<ButtonPress-3>", self.getCurrentCoords)
    Main_Window.tag_bind("move_shape", "<ButtonPress-1>", self.startMoving)
    Main_Window.tag_bind("move_shape", "<ButtonRelease-1>", self.stopMoving)
    root_window.mainloop() 
    return shape


def getCurrentCoords(self, event):
    global currentX, currentY
     #make sure the coordinates are obtained before user tries to move shape
    coords = Main_Window.coords(shapeType[0])
    currentX= coords[0]
    currentY = coords[1]
    return currentX, currentY

def startMoving(self,event):
    global b1
    b1 = "down"
    return

def stopMoving(self, event):
    global b1
    b1 = "up"
    newX = None     
    newY = None

    return b1, newX, newY

def whileMoving(self, event):
    global shapeType, b1, currentX, currentY
    if b1 == "down":
        newX = event.x
        newY = event.y
        if newX is not None  and newY is not None:
            x = newX - currentX
            y = newY - currentY
            Main_Window.move(shapeType[0],x,y)
            currentX = newX
            currentY = newY
            newX = event.x
            newY= event.y
        return
1

1 Answers

0
votes

To bind a function with arguments, use lambda keyword:

Main_Window.tag_bind(triangle, "<ButtonPress-3>", lambda shape: type1.moveShape(shape))  

If you do Main_Window.tag_bind(triangle, "<ButtonPress-3>", type1.moveShape(shape)), Python will call the callback function before creating the widget, and pass the function’s return value to Tkinter. Tkinter then attempts to convert the return value to a string, and tells Tk to call a function with that name when the button is activated. This is probably not what you wanted.

For simple cases like this, you can use a lambda expression as a link between Tkinter and the callback function (I took this explanation of effbot.org)