Drag and drop is a complex subject. Here are a collection of information, both general and Tk-specific, about Drag and Drop, as well as useful links on the matter.
AMG: I like to call it DragonDrop. :^)
There's an german explanation of the XDND protocol available at [L5 ] with a sample script for TkDND. The site contains also a complete german translation of the XDND protocol at [L6 ]. Links broken as of 2016-01-06.
More details are available in the news:comp.lang.tcl threads [L23 ] [L24 ] where this was raised.
DKF
Now we will start looking at the business of actually specifying a Tcl-level interface to drag-and-drop. Why do I start with talking about a Tcl interface instead of wading in and defining a whole bunch of C functions? Well, even a cursory read of the above references indicates that there is a lot of difference between them, so much so that writing a common C interface at this stage is very difficult. And in any case, it is the Tcl interface that is interesting to Tcl script authors. Requiring a common C interface to be defined at this stage is probably very precipitous (and would likely need to be changed a lot during its development to cope with the brain-damage of each of these mechanisms!)
It seems that defining the drag source side is much tougher (the details of the protocols that ought to be exposed to the script author are more complex there.) So we will start by looking at the target side.
The single most important "event" (this is not a standard Tk event for reasons that I'll go into later) that needs to be handled by the target side is Drop. Obviously! The following information will be available to the drop handler:
It must decide whether to proceed with the drop and how it is going to perform which action (and in that case transfer the dragged data) or whether to reject the drop. It is because of the fact that we need to indicate whether a drop failed or succeeded that we cannot use a normal Tk event. Instead, it looks like something involving callbacks with passed arguments (rather like [trace variable] callbacks?)
Also need DragEnter, DragMotion and DragLeave. And we need a mechanism for providing some commonality for datatype names, since although a piece of text is a piece of text pretty much everywhere, the name for it is not always the same. My hunch is that using MIME types is a good idea; everyone knows what text/plain is. We can then also provide a reasonable algorithm for deciding when to do line-terminator conversions (do it for all text/* and nothing else.)
There probably ought to be a mechanism to ask for no further Drag* notifications when within a particular area, as this would allow some targets to significantly reduce the amount of work they do.
On this last point, X certainly supports this sort of behavior, though it depends on whether the window manager performs auto-raise operations. (Some do, some don't, and most are configurable.)
- DKF
I think it's important to have a simple, minimal protocol up soon that allows dropping onto widgets and accepts some obvious string format. Pretty much all major other toolkits have this now (wxWindows, GTK+, Qt, MFC, etc.). Most applications of drag-and-drop can be built with some simple support like that.
Tcl/Tk has always tried to make the common case work well and I think it would be good to continue that philosophy.
Getting coordinates, drag-over feedback, multiple data formats, etc. are niceties that could be added later but may not even be supportable on all platforms.
Java, incidentally, just uses the native drag-and-drop interfaces as much as possible, so there should not be a big problem inter-operating with it. Java DND works, for example, with GTK and Windows.
(tmb at aimnet.com)
I've been using tkdnd a fair bit, and it's led me to conclude that any full dnd implementation must have a data-handle-callback mechanism. This is because information on the drag/drop may potentially be megabytes (contents of a file) or not, and may be in different possible formats, and the drag handler (i.e., Tk) must be able to request at least some attributes of the data to be able to determine if a drop is to be allowed. This should happen during the drag action, not once the user has already dropped something.
Example 1: tkdnd won't currently provide the %D data field during DragEnter or Drag events, which means all Tk has to go on is that the dragged item is, say, a file. No name is provided, even. So, a widget cannot even filter its drag events based upon file extension. (Note: as of Jan 2004, George has a private development version of tkdnd which on Windows does provide this information).
Example 2: tkdnd contains preliminary support for a 'FileDescriptor' -- this is a file that doesn't really exist -- say a file displayed in a browser window's ftp site listing, or a file displayed in a virtual-filesystem listing. We want to be able to drag such a file and then, if and only if the drop is successful do we want to access the contents of the file through a callback mechanism.
A quick implementation of this would be quite easy: the drag/drop receiver would get an opaque handle, and could call 'dnd getdata $draghandle' to get the contents. However, it could be that this is more complex, and there may be different possible formats in which the data is available. One quite general solution would be like 'file attributes', and have a platform-specific 'drag attributes $draghandle' (hopefully some elements of which are cross-platform!).
More comments/details/ideas are deeply welcome! DKF
SES_home - 2009-12-31 14:25:46
Hello all, I would like to share with you, a simple implementation of Drag-And-Drop between listbox type widgets (as implemented in tG² v1.05.02 and higher )
# Purpose : to process the dropped element inside the target widget proc place_listbox_proccess_DAD {args} { global DAD_content [lindex $args 0] insert end $DAD_content } # Purpose : enables Drag-And-Drop controls of any listbox widget proc place_listbox_controls_DAD {w {cutOrig 0} {procName "place_listbox_proccess_DAD"}} { bind $w <ButtonPress-1> {+; set DAD_pressed 1 } bind $w <Motion> {+; if {[catch {set DAD_pressed $DAD_pressed}]} {set DAD_pressed 0} if {$DAD_pressed} { %W config -cursor exchange if {[catch {set DAD_content [%W get [%W curselection]]}]} { set DAD_pressed 0 } } else { %W config -cursor "" } } if $cutOrig {set cutCmd "$w delete \[$w curselection\]"} else {set cutCmd ""} if {$procName == ""} {set procName place_listbox_proccess_DAD} set cmd "bind $w \<ButtonRelease-1\> \{+\; $w config -cursor \"\" set DAD_pressed 0 if \{\[catch \{set DAD_content \$DAD_content\}\]\} \{set DAD_content \"\"\} if \{\$DAD_content != \"\"\} \{ set wDAD \[winfo containing \[winfo pointerx .\] \[winfo pointery .\]\] if \{\(\$wDAD ne \"\"\) && \(\$wDAD != \"\%W\"\)\} \{ if !\[catch \{$procName \$wDAD\}\] \{$cutCmd\} \} set DAD_content \"\" \} \}" eval $cmd } # ---------- TEST CODE ------------------------ listbox .ls1 -height 20 -width 10 foreach item {a b c d e} {.ls1 insert end $item} listbox .ls2 -height 20 -width 10 foreach item {f g h i j} {.ls2 insert end $item} place .ls1 -x 10 -y 50 place .ls2 -x 100 -y 50 place_listbox_controls_DAD .ls1 place_listbox_controls_DAD .ls2 1
ThePianist - 2010-11-13 08:26:46
Hi. I am trying to do drag and drop in a ttk tree. Anyone can tell me the changes i have to make relatively to this code? Thanks!