from PIL import Image, ImageTk # Если выдаёт ImportError, установи его командой
import tkinter # python -m pip install pillow
def dnd_start(source, event):
h = DndHandler(source, event)
if h.root:
return h
else:
return None
class DndHandler:
root = None
def __init__(self, source, event):
if event.num > 5:
return
root = event.widget._root()
try:
root.__dnd
return # Don't start recursive dnd
except AttributeError:
root.__dnd = self
self.root = root
self.source = source
[self.target](http://self.target) = None
self.initial_button = button = event.num
self.initial_widget = widget = event.widget
self.release_pattern = "<B%d-ButtonRelease-%d>" % (button, button)
self.save_cursor = widget['cursor'] or ""
widget.bind(self.release_pattern, self.on_release)
widget.bind("<Motion>", self.on_motion)
widget['cursor'] = "hand2"
def __del__(self):
root = self.root
self.root = None
if root:
try:
del root.__dnd
except AttributeError:
pass
def on_motion(self, event):
x, y = event.x_root, event.y_root
target_widget = self.initial_widget.winfo_containing(x, y)
source = self.source
new_target = None
while target_widget:
try:
attr = target_widget.dnd_accept
except AttributeError:
pass
else:
new_target = attr(source, event)
if new_target:
break
target_widget = target_widget.master
old_target = [self.target](http://self.target)
if old_target is new_target:
if old_target:
old_target.dnd_motion(source, event)
else:
if old_target:
[self.target](http://self.target) = None
old_target.dnd_leave(source, event)
if new_target:
new_target.dnd_enter(source, event)
[self.target](http://self.target) = new_target
def on_release(self, event):
self.finish(event, 1)
def cancel(self, event=None):
self.finish(event, 0)
def finish(self, event, commit=0):
target = [self.target](http://self.target)
source = self.source
widget = self.initial_widget
root = self.root
try:
del root.__dnd
self.initial_widget.unbind(self.release_pattern)
self.initial_widget.unbind("<Motion>")
widget['cursor'] = self.save_cursor
[self.target](http://self.target) = self.source = self.initial_widget = self.root = None
if target:
if commit:
target.dnd_commit(source, event)
else:
target.dnd_leave(source, event)
finally:
source.dnd_end(target, event)
class Icon:
def __init__(self, image):
[self.name](http://self.name) = image
self.canvas = self.label = [http://self.id](http://self.id) = None
def attach(self, canvas, x=10, y=10):
if canvas is self.canvas:
self.canvas.coords(self
.id, x, y)
return
if self.canvas:
self.detach()
if not canvas:
return
label = tkinter.Label(canvas, [image=self.name](http://image=self.name),
borderwidth=2, relief="raised")
id = canvas.create_window(x, y, window=label, anchor="nw")
self.canvas = canvas
self.label = label
[self.id](http://self.id) = id
label.bind("<ButtonPress>", [self.press](http://self.press))
def detach(self):
canvas = self.canvas
if not canvas:
return
id = [self.id](http://self.id)
label = self.label
self.canvas = self.label = [self.id](http://self.id) = None
canvas.delete(id)
label.destroy()
def press(self, event):
if dnd_start(self, event):
# where the pointer is relative to the label widget:
self.x_off = event.x
self.y_off = event.y
# where the widget is relative to the canvas:
self.x_orig, self.y_orig = self.canvas.coords([self.id](http://self.id))
def move(self, event):
x, y = self.where(self.canvas, event)
self.canvas.coords([self.id](http://self.id), x, y)
def putback(self):
self.canvas.coords([self.id](http://self.id), self.x_orig, self.y_orig)
def where(self, canvas, event):
# where the corner of the canvas is relative to the screen:
x_org = canvas.winfo_rootx()
y_org = canvas.winfo_rooty()
# where the pointer is relative to the canvas widget:
x = event.x_root - x_org
y = event.y_root - y_org
# compensate for initial pointer offset
return x - self.x_off, y - self.y_off
def dnd_end(self, target, event):
pass
class Root([tkinter.Tk](http://tkinter.Tk)):
def __init__(self):
super().__init__()
self.canvas = tkinter.Canvas(width=100, height=100)
[self.canvas.place](http://self.canvas.place)(relwidth = 1, relheight = 1)
self.canvas.dnd_accept = self.dnd_accept
def dnd_accept(self, source, event):
return self
def dnd_enter(self, source, event):
self.canvas.focus_set() # Show highlight border
x, y = source.where(self.canvas, event)
x1, y1, x2, y2 = source.canvas.bbox([source.id](http://source.id))
dx, dy = x2-x1, y2-y1
self.dndid = self.canvas.create_rectangle(x, y, x+dx, y+dy)
self.dnd_motion(source, event)
def dnd_motion(self, source, event):
x, y = source.where(self.canvas, event)
x1, y1, x2, y2 = self.canvas.bbox(self.dndid)
self.canvas.move(self.dndid, x-x1, y-y1)
def dnd_leave(self, source, event):
self.focus_set() # Hide highlight border
self.canvas.delete(self.dndid)
self.dndid = None
def dnd_commit(self, source, event):
self.dnd_leave(source, event)
x, y = source.where(self.canvas, event)
source.attach(self.canvas, x, y)
, y, x+dx, y+dy)
self.dnd_motion(source, event)
def dnd_motion(self, source, event):
x, y = source.where(self.canvas, event)
x1, y1, x2, y2 = self.canvas.bbox(self.dndid)
self.canvas.move(self.dndid, x-x1, y-y1)
def dnd_leave(self, source, event):
self.focus_set() # Hide highlight border
self.canvas.delete(self.dndid)
self.dndid = None
def dnd_commit(self, source, event):
self.dnd_leave(source, event)
x, y = source.where(self.canvas, event)
source.attach(self.canvas, x, y)
root = Root()
icon = Icon(ImageTk.PhotoImage([Image.open](http://Image.open)('D:/фото/cat_relax.png')))
icon.attach(root.canvas)
root.mainloop()
icon.attach(root.canvas)
root.mainloop()
Этот код очень большой, неудобный и так далее, но я смог это.
Что-нибудь непонятно — пиши в комментарии.
Этот хренов бот Яндекс.Ку зачем-то подменяет некоторые вызовы методов и объектов на ССЫЛКИ.