user2148990 user2148990 - 5 months ago 21
Python Question

Tkinter drag and drop

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

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