9

Currently, I am working with Python 3.5 GUI development using tkinter module. I want to be able to drag an image from one place to another within the application. Does tkinter support drag and drop within an application, and if so, how do you do it?

from tkinter import *

root = Tk()
root.geometry("640x480")

canvas = Canvas(root, height=480, width=640, bg="white")

frame = Frame(root, height=480, width=640, bg="white")
frame.propagate(0)

image = PhotoImage(file="C:/Users/Shivam/Pictures/Paint/Body.png")

label = Label(canvas, image=image)
label.pack()

label_2 = Label(frame, text="Drop Here !")
label_2.pack()
label_2.place(x=200, y=225, anchor=CENTER)

canvas.pack(side=LEFT)
frame.pack()

root.mainloop()
martineau
  • 119,623
  • 25
  • 170
  • 301
  • Do you mean I should write a example on what I want to drag ? –  Jul 03 '17 at 14:16
  • I don't know what @Donal expects you to have tried to write. There **is** an experimental DND tkinter module. See [this answer](https://stackoverflow.com/a/37281311/355230). Also see article [**_Drag-n-drop for Python/Tkinter howto_**](http://www.bitflipper.ca/Documentation/Tkdnd.html). – martineau Jul 03 '17 at 14:27
  • @martineau Thank you ! –  Jul 03 '17 at 14:35
  • @martineau: you don't need the experimental module if all you're doing is dragging and dropping within the app itself. – Bryan Oakley Jul 03 '17 at 14:43
  • What do you mean by "drag and drop interface"? Certainly, tkinter has the ability to run custom code on button clicks, button movement, and button releases -- all of the basic building blocks of drag and drop. – Bryan Oakley Jul 03 '17 at 14:44
  • @BryanOakley I have an image on a widget label(eg. label = Label(canvas, image=myimage) and it shows up. Now I want to drag it and drop it on a frame or some other canvas. –  Jul 03 '17 at 14:46
  • @DonalFellows Do you still think it is duplicate ? –  Jul 03 '17 at 14:56
  • @BryanOakley: Since the OP is asking about within the app, then this **is** a duplicate question. Tkdnd / dnd.py is for that scenario, I believe, and there are sereral other question about the topic with answer(s) related to using it. – martineau Jul 03 '17 at 15:30
  • @martineau: that other question explicitly states "I should stress that I am talking about drag/drop between different applications". This one is explicitly about dragging within an application, which doesn't require tkdnd. I tried to modify the question to make it more clear how this question is different from that other one. – Bryan Oakley Jul 03 '17 at 15:33
  • 1
    @martineau: yes, it definitely looks like a dupe of that one. It's definitely a different question than the first one it was marked a duplicate of, however. – Bryan Oakley Jul 03 '17 at 15:40
  • @Shivam: I suggest you use [wxPython](https://wxpython.org/) which has better DnD support than tkinter from what I've read. – martineau Jul 03 '17 at 15:45
  • Ugh. I tried for about a year and a half to use wxPython. While it looks prettier, it's much harder to use IMO. – Bryan Oakley Jul 03 '17 at 16:32

2 Answers2

16

Tkinter doesn't have any direct support for drag and drop within an application. However, drag and drop requires not much more than making suitable bindings for a button click (<ButtonPress-1>), the mouse moving while the button is clicked (<B1-Motion>), and when the button is released (<ButtonRelease-1>).

Here is a very simplestic example which is designed to work with your code.

First, we'll create a class that can manage the dragging and dropping. It's easier to do this as a class rather than a collection of global functions.

class DragManager():
    def add_dragable(self, widget):
        widget.bind("<ButtonPress-1>", self.on_start)
        widget.bind("<B1-Motion>", self.on_drag)
        widget.bind("<ButtonRelease-1>", self.on_drop)
        widget.configure(cursor="hand1")

    def on_start(self, event):
        # you could use this method to create a floating window
        # that represents what is being dragged.
        pass

    def on_drag(self, event):
        # you could use this method to move a floating window that
        # represents what you're dragging
        pass

    def on_drop(self, event):
        # find the widget under the cursor
        x,y = event.widget.winfo_pointerxy()
        target = event.widget.winfo_containing(x,y)
        try:
            target.configure(image=event.widget.cget("image"))
        except:
            pass

To use it, all you need to do is call the add_draggable method, giving it the widget(s) you wish to drag.

For example:

label = Label(canvas, image=image)
...
dnd = DragManager()
dnd.add_dragable(label)
...
root.mainloop()

That's all it takes for the basic framework. It's up to you to create a floating draggable window, and to perhaps highlight the item(s) that can be dropped on.

Other implementations

For another implementation of the same concept, see https://github.com/python/cpython/blob/master/Lib/tkinter/dnd.py

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • 1
    Thank you so much sir ... This is what I needed ! Thanks a lot for help ! –  Jul 03 '17 at 15:35
  • 1
    @Bryan Oakley, How do I get the path of the file that I'm dragging ? – Uchiha Madara Dec 06 '17 at 12:06
  • @UchihaMadara: How can I answer that? I have no idea what your code looks like. – Bryan Oakley Dec 06 '17 at 12:44
  • I'm planning to create an editor to write text and drag'n'drop images. I wanna be able to drag the image into editor and use `Label` widget to place it into the editor. But `Label` needs image path. So I wanna get the path of the image when I drop into the editor, so I can pass it to `label`. ( haven't written code yet.) – Uchiha Madara Dec 06 '17 at 13:09
  • Your great answer is missing on the closed to duplicate: https://stackoverflow.com/questions/37280004/tkinter-how-to-drag-and-drop-widgets – WinEunuuchs2Unix Jun 13 '23 at 17:53
4

https://github.com/akheron/cpython/blob/master/Lib/tkinter/dnd.py
I tested it and it still seems to work in python 3.6.1, I suggest experimenting with it and making it your own, because it doesn't seem to be officially supported in Tkinter.

Maxis
  • 384
  • 2
  • 13
  • Thank you for quick response ! But it's not duplicate ! I said I use tkinter. I don't even know if there is a function for it or not. –  Jul 03 '17 at 14:15
  • I accidentally voted your question down and can't change my vote unless you make an edit to the answer. If you remove the comment about this being a possible dupe I'll change my vote. – Bryan Oakley Jul 03 '17 at 15:38
  • I removed the thing about the duplicate – Maxis Jul 04 '17 at 08:28