import tkinter as tk
import math
class DraggableCanvas(tk.Canvas):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
self.bind("<ButtonPress-1>", self.on_left_press)
self.bind("<ButtonPress-3>", self.on_right_press)
self.bind("<ButtonRelease-3>", self.on_right_release)
self.selected_item = None
self.move_targets = {} # item_id -> (target_x, target_y)
self.moving_items = set() # item_id -> currently animating
# Пример объектов
self.create_oval(50, 50, 100, 100, fill="red", tags="draggable")
self.create_rectangle(150, 150, 200, 200, fill="blue", tags="draggable")
def on_left_press(self, event):
items = self.find_overlapping(event.x, event.y, event.x, event.y)
for item in reversed(items):
if "draggable" in self.gettags(item):
self.selected_item = item
break
def on_right_press(self, event):
if self.selected_item:
self.move_targets[self.selected_item] = (event.x, event.y)
def on_right_release(self, event):
if self.selected_item and self.selected_item in self.move_targets:
if self.selected_item not in self.moving_items:
self.moving_items.add(self.selected_item)
self.animate_move(self.selected_item)
def animate_move(self, item_id, speed=1):
if item_id not in self.move_targets:
self.moving_items.discard(item_id)
return
target_x, target_y = self.move_targets[item_id]
coords = self.bbox(item_id)
if coords is None:
self.moving_items.discard(item_id)
return
x0 = (coords[0] + coords[2]) / 2
y0 = (coords[1] + coords[3]) / 2
dx = target_x - x0
dy = target_y - y0
distance = math.hypot(dx, dy)
if distance < 5:
self.moving_items.discard(item_id)
return
step_x = dx / distance * speed
step_y = dy / distance * speed
self.move(item_id, step_x, step_y)
self.after(20, lambda: self.animate_move(item_id, speed))
if __name__ == "__main__":
root = tk.Tk()
root.title("Плавное перемещение объектов")
canvas = DraggableCanvas(root, width=500, height=400, bg="white")
canvas.pack(fill="both", expand=True)
root.mainloop()
исправил ускорение при повторном нажатии