Теперь Кью работает в режиме чтения

Мы сохранили весь контент, но добавить что-то новое уже нельзя

Как перемещать картинки в tkinter?

ПрограммированиеTkinter
Макс Евтишкин
  ·   · 642
Самоучка на Пайтон 3. Дискорд: NordGamer#5580   · 17 окт 2021
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()
Этот код очень большой, неудобный и так далее, но я смог это.
Что-нибудь непонятно — пиши в комментарии.
Этот хренов бот Яндекс.Ку зачем-то подменяет некоторые вызовы методов и объектов на ССЫЛКИ.