Moving items using drag and drop
At the window level, PowerBuilder provides functions and
properties for dragging controls onto other controls. Within the
TreeView, you can also let the user drag items onto other items. Users
might drag items to sort them, move them to another branch, or put child
items under a parent.
When you implement drag and drop as a way to move items, you
decide whether the dragged item becomes a sibling or child of the
target, whether the dragged item is moved or copied, and whether its
children get moved with it.
There are several properties and events that you need to
coordinate to implement drag and drop for items, as shown in the
following table.
|
Property or event |
Setting or purpose |
|---|---|
|
DragAuto property |
TRUE or FALSE If FALSE, you must call |
|
DisableDragDrop property |
FALSE |
|
DragIcon property |
An appropriate or None!, which means the user |
|
BeginDrag event |
Script for saving the handle of the dragged item |
|
DragWithin event |
Script for highlighting drop targets |
|
DragDrop event |
Script for implementing the result of the drag |
Example
The key to a successful drag-and-drop implementation is in the
details. This section illustrates one way of moving items. In the
example, the dragged item becomes a sibling of the drop target, inserted
after it. All children of the item are moved with it and the original
item is deleted.
A function called recursively moves the children, regardless of
the number of levels. To prevent an endless loop, an item cannot become
a child of itself. This means a drop target that is a child of the
dragged item is not allowed.
BeginDrag event
The script saves the handle of the dragged item in an instance
variable:
|
1 |
ll_dragged_tvi_handle = handle |
If you want to prevent some items from being dragged — such as
items at a particular level — that code goes here too:
|
1 2 3 |
TreeViewItem tvi This.GetItem(handle, tvi) IF tvi.Level = 3 THEN This.Drag(Cancel!) |
DragWithin event
The script highlights the item under the cursor so the user can
see each potential drop target. If only some items are drop targets,
your script should check an item’s characteristics before highlighting
it. In this example, you could check whether an item is a parent of the
dragged item and highlight it only if it is not:
|
1 2 3 4 |
TreeViewItem tvi This.GetItem(handle, tvi) tvi.DropHighlighted = TRUE This.SetItem(handle, tvi) |
DragDrop event
This script does all the work. It checks whether the item can be
inserted at the selected location and inserts the dragged item in its
new position a sibling after the drop target. Then it calls a function
that moves the children of the dragged item too:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
TreeViewItem tvi_src, tvi_child long h_parent, h_gparent, h_moved, h_child integer rtn // Get TreeViewItem for dragged item This.GetItem(ll_dragged_tvi_handle, tvi_src) // Don't allow moving an item into its own branch, // that is, a child of itself h_gparent = This.FindItem(ParentTreeItem!, handle) DO WHILE h_gparent <> -1 IF h_gparent = ll_dragged_tvi_handle THEN MessageBox("No Drag", & "Can't make an item a child of itself.") RETURN 0 END IF h_gparent=This.FindItem(ParentTreeItem!, h_gparent) LOOP // Get item parent for inserting h_parent = This.FindItem(ParentTreeItem!, handle) // Use 0 if no parent because target is at level 1 IF h_parent = -1 THEN h_parent = 0 // Insert item after drop target h_moved = This.InsertItem(h_parent, handle, tvi_src) IF h_moved = -1 THEN MessageBox("No Dragging", "Could not move item.") RETURN 0 ELSE // Args: old parent, new parent rtn = uf_movechildren(ll_dragged_tvi_handle, & h_moved) / If all children are successfully moved, // delete original item IF rtn = 0 THEN This.DeleteItem(ll_dragged_tvi_handle) END IF END IF |
The DragDrop event script shown above calls the function
uf_movechildren. The function calls itself recursively so that all the
levels of children below the dragged item are moved:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
// Function: uf_movechildren // Arguments: // oldparent - Handle of item whose children are // being moved. Initially, the dragged item in its // original position // // newparent - Handle of item to whom children are // being moved. Initially, the dragged item in its // new position. long h_child, h_movedchild TreeViewItem tvi // Return -1 if any Insert action fails // Are there any children? h_child = tv_2.FindItem(ChildTreeItem!, oldparent) IF h_child <> -1 THEN tv_2.GetItem(h_child, tvi) h_movedchild = tv_2.InsertItemLast(newparent, tvi) IF h_movedchild = -1 THEN RETURN -1 // Move the children of the child that was found uf_movechildren(h_child, h_movedchild) // Check for more children at the original level h_child = tv_2.FindItem(NextTreeItem!, h_child) DO WHILE h_child <> -1 tv_2.GetItem(h_child, tvi) h_movedchild= tv_2.InsertItemLast(newparent,tvi) IF h_movedchild = -1 THEN RETURN -1 uf_movechildren(h_child, h_movedchild) // Any more children at original level? h_child = tv_2.FindItem(NextTreeItem!, h_child) LOOP END IF RETURN 0 // Success, all children moved |