The drag and drop action is a standard action in computer interfaces. In the case of list boxes, pressing the “Alt” key is necessary to move several items simultaneously. Or rather “was” because, starting with 4D v19 R7, this is no longer a requirement at all!
A more user-friendly interface
This operation required pressing the “alt” key on the keyboard for technical and historical reasons to move several elements simultaneously. This obligation is now a thing of the past. This is a user-friendly improvement because this new behavior is very close to the one used by macOS or Windows to manage files and folders. Users won’t get confused, and this action will be very natural!
If users of existing applications are used to pressing the alt-key while dragging, there is nothing to worry about. The drag and drop will work the exact same way. The alt key shall be ignored unless you program something to take it into account for any other purpose (ex: if the alt key is down, the copy instead of just move).
The new behavior is more user-friendly because it mimics operating systems, and most applications work. We could stop here but let’s take this opportunity to remind some principles of how list boxes work, their properties, and the events that can be handled. If you’re interested, let’s go on!
Selection modes. Multi-selection. and events
Three possible selection modes
Listboxes have three selection modes determined by a property of the property list.
Two possible multi-selection modes.
Selecting several elements is possible by using the keyboard keys.
- By holding down the shift key, you can create a continuous selection (ex: From “Chloe” to “Mike”)
- By holding down the Ctrl key (Cmd key on macOS), you can create a discontinuous selection (ex: “Albert” and “John” and “Mike” and “Peter”)
Three events can be managed during “drag and drop.”
- on beginning drag over
- on drag over
- on drop
Important note: These events shall be triggered only if the actions settings for draggable and droppable are set to custom.
1 – The first one (on beginning drag over) is triggered when the drag starts in the “source” listbox. At this point, it is necessary to prepare “the next step,” i.e., to look at what is selected and store it in some way. This can be inside the clipboard or in a form variable, for example. Note that this event is triggered only once.
If (Form event code=On Begin Drag Over) $drag:=New object // (…) put what you need in Form.drag object // put the object in a BLOB VARIABLE TO BLOB($drag; $blob) // and send the object to the PasteBoard with any signature (xxxx) APPEND DATA TO PASTEBOARD("xxxx"; $blob) End if
2 – The second one (on drag over) is triggered on hovering over a listbox but only when it has been preceded by an on beginning drag over or if anything else can be dropped on the listbox.
It is not mandatory to consider this event, but it is beneficial because it allows refusing a possible “drop” that could occur later.
How to do this? You just have to look at the content of what is likely to be dropped. If you’re okay with what can be dropped, return 0 (zero) in $0. Otherwise, return -1 (minus one), then the drop will be refused (and no “on drop” event will be generated)
If (Form event code=On Drag Over) If (Pasteboard data size("xxxx")<=0) $0:=-1 //reject anything that does NOT contains what is expected Else $0:=0 End if End if
3 – Finally, the third one (on the drop) is generated, as its name indicates, at the moment when a “drop” is actually performed on the “target” listbox (which can be the same as the source).
From then on, you can test at which position the drop has been made and perform the necessary operations depending on the content to be dropped. Don’t forget that the drop is not necessarily the logical consequence of a drag from another listbox (or the listbox itself). It can also be an external element, even external to the application, such as a file or a folder from the system environment.
if(Form event code=On Drop) // read pasteboard content GET PASTEBOARD DATA("xxxx"; $blob) BLOB TO VARIABLE($blob; $drag) // do what you need to do with the object you got (…) end if
All this information is covered in the HDI sample, which we invite you to download to see a practical implementation.