Board-Drawing Code to Move an Oval

Tkinter drag and drop

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

How do you use a button to move items on a canvas in Python?

command= executes function without event but you assign function which expects event - command=self.button_move -> def button_move(self, event)

But bind executes the same function with event so you need this function with event.

Solution: use default value for event, ie None

def button_move(self, event=None):

But you can't use event.x, event.y in this function if you what to execute with command=

Modifying code to drag strings

Is this what you are looking for:

import tkinter as tk

class SampleApp(tk.Tk):
'''Illustrate how to drag items on a Tkinter canvas'''

def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)

# create a canvas
self.canvas = tk.Canvas(width=400, height=400, bg='red')
self.canvas.pack(fill="both", expand=True)

# this data is used to keep track of an
# item being dragged
self._drag_data = {"x": 0, "y": 0, "item": None}

# create a couple movable objects
self._create_token((100, 100), "white", "User")
self._create_token((200, 100), "black", "Ryan")

# add bindings for clicking, dragging and releasing over
# any object with the "token" tag
self.canvas.tag_bind("token", "<ButtonPress-1>", self.OnTokenButtonPress)
self.canvas.tag_bind("token", "<ButtonRelease-1>", self.OnTokenButtonRelease)
self.canvas.tag_bind("token", "<B1-Motion>", self.OnTokenMotion)

def _create_token(self, coord, color, mytext):
'''Create a token at the given coordinate in the given color'''
(x,y) = coord
self.canvas.create_text(x-25, y-25,
fill=color, tags="token", text=mytext)

def OnTokenButtonPress(self, event):
'''Being drag of an object'''
# record the item and its location
self._drag_data["item"] = self.canvas.find_closest(event.x, event.y)[0]
self._drag_data["x"] = event.x
self._drag_data["y"] = event.y

def OnTokenButtonRelease(self, event):
'''End drag of an object'''
# reset the drag information
self._drag_data["item"] = None
self._drag_data["x"] = 0
self._drag_data["y"] = 0

def OnTokenMotion(self, event):
'''Handle dragging of an object'''
# compute how much this object has moved
delta_x = event.x - self._drag_data["x"]
delta_y = event.y - self._drag_data["y"]
# move the object the appropriate amount
self.canvas.move(self._drag_data["item"], delta_x, delta_y)
# record the new position
self._drag_data["x"] = event.x
self._drag_data["y"] = event.y

if __name__ == "__main__":
app = SampleApp()
app.mainloop()

?


What I changed:

(EDITED LINES: 10, 18, 19, 27, 30 and 31)

-canvas background color from default (white) to red to identify white and black objects on it better;

-self.canvas.create_oval to self.canvas.create_text since you want strings instead of ovals;

-also, removed the second couple of coordinates (x+25, y+25) since create_text requires only one couple of coordinates (create_oval requires two of them), and removed outline=color since a text object doesn't have outline option, so Tkinter returns an unknown option error;

-and finally, after changing it from create_oval to create_text, I had to add the text option mytext to the _create_token function (def _create_token(self, coord, color, mytext):) and its instances ("User" & "Ryan") to the movable objects:

self._create_token((100, 100), "white", "User")
self._create_token((200, 100), "black", "Ryan")
.

how to drag entire contents in a rectangle using tkinter python?

In drag_start() I use outer rectangle to get its region and add tag "drag" to all elements which are fully inside this region

rect = self.canvas.bbox(self._drag_data["item"])

self.canvas.addtag_enclosed("drag", *rect)

In dra() I move all elements with tag "drag"

self.canvas.move("drag", delta_x, delta_y)

In drag_stop() I remove tag "drag" from all elements which have tag "drag"

self.canvas.dtag("drag", "drag")

This way outer rectangle can move also inner rectangle. But if you move inner rectangle then inner rectangle doesn't move. If you want outer rectangle when you move innter rectangle then maybe you should use tag "token"

self.canvas.move("token", delta_x, delta_y)

import tkinter as tk     # python 3
# import Tkinter as tk # python 2

class Example(tk.Frame):
"""Illustrate how to drag items on a Tkinter canvas"""

def __init__(self, parent):
tk.Frame.__init__(self, parent)

# create a canvas
self.canvas = tk.Canvas(width=400, height=400, background="bisque")
self.canvas.pack(fill="both", expand=True)

# this data is used to keep track of an
# item being dragged
self._drag_data = {"x": 0, "y": 0, "item": None}

# create a couple of movable objects
#self.create_token(50, 100, "white")
self.create_token(200, 100, "black")
self.create_token1(200,100,"white")
# add bindings for clicking, dragging and releasing over
# any object with the "token" tag
self.canvas.tag_bind("token", "<ButtonPress-1>", self.drag_start)
self.canvas.tag_bind("token", "<ButtonRelease-1>", self.drag_stop)
self.canvas.tag_bind("token", "<B1-Motion>", self.drag)

def create_token(self, x, y, color):
"""Create a token at the given coordinate in the given color"""
self.canvas.create_rectangle(
x - 25,
y - 25,
x + 25,
y + 25,
outline=color,
fill=color,
tags=("token",),
)

def create_token1(self,x,y,color):

self.canvas.create_rectangle(
x - 25,
y - 10,
x + 25,
y + 10,
outline=color,
fill=color,
tags=("token",),
)

def drag_start(self, event):
"""Begining drag of an object"""
# record the item and its location
self._drag_data["item"] = self.canvas.find_closest(event.x, event.y)[0]

rect = self.canvas.bbox(self._drag_data["item"])
self.canvas.addtag_enclosed("drag", *rect)
print(rect)

self._drag_data["x"] = event.x
self._drag_data["y"] = event.y

def drag_stop(self, event):
"""End drag of an object"""
# reset the drag information
self._drag_data["item"] = None
self._drag_data["x"] = 0
self._drag_data["y"] = 0
self.canvas.dtag("drag", "drag")

def drag(self, event):
"""Handle dragging of an object"""
# compute how much the mouse has moved
delta_x = event.x - self._drag_data["x"]
delta_y = event.y - self._drag_data["y"]

# move the object the appropriate amount
#self.canvas.move(self._drag_data["item"], delta_x, delta_y)
self.canvas.move("drag", delta_x, delta_y)

# record the new position
self._drag_data["x"] = event.x
self._drag_data["y"] = event.y

if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()


Related Topics



Leave a reply



Submit