Tkinter drag and drop

user2148990 picture user2148990 · Mar 17, 2013 · Viewed 13.7k times · Source

I'm working on a drag and drop function that will allow me to move items around on a canvas.I have it working (Kind of) but I move only slightly but the line shoots across the screen (And eventually off the visible part of the canvas so I cannot get to it. I'm not sure where to go from here. Below is the drag and drop code I've created so far:

def onPressToMove(self, event): #get initial location of object to be moved
    winX = event.x - self.workspace.canvasx(0)
    winY = event.y - self.workspace.canvasy(0)
    self.dragInfo["Widget"] = self.workspace.find_closest(event.x, event.y, halo = 5)[0]
    self.dragInfo["xCoord"] = winX
    self.dragInfo["yCoord"] = winY

def onReleaseToMove(self, event): #reset data on release
    self.dragInfo["Widget"] = None
    self.dragInfo["xCoord"] = 0
    self.dragInfo["yCoord"] = 0        

def onMovement(self, event):
    winX = event.x - self.workspace.canvasx(0)
    winY = event.y - self.workspace.canvasy(0)
    newX = winX - self.dragInfo["xCoord"]
    newY = winY - self.dragInfo["yCoord"]
    self.workspace.move(self.dragInfo["Widget"], newX, newY)

dragInfo is a dictionary I'm using to store the data. Originally I thought that translating the canvas coordinates to window coordinates would help, but it acts the same as without that stuff.

Answer

Bryan Oakley picture Bryan Oakley · Mar 17, 2013

This answer to the question "board drawing code to move an oval" shows how to drag an object on a canvas.

In your case, you're not resetting the base of the delta as you move the object. If the mouse moves one pixel to the right, you use move to move the mouse one pixel to the right.

Now, let's say you move it one more pixel to the right. This time, your calculation says the delta is 2 from the starting point even though you only actually moved the mouse one more pixel). Next time you move one pixel, you're calculating a delta of 3, and so on.

The solution is simple: reset dragInfo["xCoord"] and dragInfo["yCoord"] while it is moving, since you only want to compute the delta to its previous position, not the original starting position.

def onPressToMove(self, event): #get initial location of object to be moved
    winX = event.x - self.canvas.canvasx(0)
    winY = event.y - self.canvas.canvasy(0)
    self.dragInfo["Widget"] = self.canvas.find_closest(event.x, event.y, halo = 5)[0]

    # reset the starting point for the next move
    self.dragInfo["xCoord"] = winX
    self.dragInfo["yCoord"] = winY