ACC97: Example Using TreeView Control Drag-and-Drop Capabilities

ID: Q165993

The information in this article applies to:

SUMMARY

Advanced: Requires expert coding, interoperability, and multiuser skills.

This article shows you an annotated example that demonstrates how to use drag-and-drop functionality in the Microsoft TreeView control, version 5.0.

The Microsoft TreeView control, version 5.0 ships with Microsoft Office 97 Developer Edition.

This article assumes that you are familiar with Visual Basic for Applications and with creating Microsoft Access applications using the programming tools provided with Microsoft Access. For more information about Visual Basic for Applications, please refer to the "Building Applications with Microsoft Access 97" manual.

MORE INFORMATION

The Microsoft TreeView control, version 5.0 features built-in drag-and-drop functionality that was not available in earlier versions. It supports drag- and-drop events, such as OLEStartDrag, OLEDragOver, OLECompleteDrag and OLEDragDrop.

The following example creates a hierarchical list of employees in the Northwind sample database. The TreeView control displays employees according to whom they report to and enables you to drag employee names to reorder the hierarchy and update the underlying table.

CAUTION: Following the steps in this example will modify the sample database Northwind.mdb. You may want to back up the Northwind.mdb file and perform these steps on a copy of the database.

 1. Start Microsoft Access 97 and open the sample database Northwind.mdb.

 2. Create a new form not based on any table or query in Design view.

 3. On the Insert menu, click ActiveX Control.

 4. In the Insert ActiveX Control dialog box, select the Microsoft TreeView
    Control, version 5.0, and then click OK.

 5. Set the following properties for the TreeView control:

      Name: xTree
      Width: 3"
      Height" 2"

 6. Double-click the TreeView control to set its custom properties on the
    General tab of the TreeCtrl Properties dialog box:

      Style: 6 - tvwTreelinesPlusMinusText
      LineStyle: 1 - tvwRootLines
      OLEDragMode: 1 - ccOLEDragAutomatic
      OLEDropMode: 1 - ccOLEDropManual

   Click OK.

 7. Save the form as TreeViewTest.

 8. On the View menu, click Code.

 9. Type the following procedures:

      '==================================================================
      ' This procedure populates the TreeView control when the form opens
      '==================================================================
      Private Sub Form_Load()
      On Error GoTo ErrForm_Load
      Dim db As Database, rst As Recordset, nodCurrent As Node
      Dim objTree As TreeView, strText As String, nodRoot As Node
      Dim bk As String

      Set db = CurrentDb
      ' Open the Employees table.
      Set rst = db.OpenRecordset("Employees", dbOpenDynaset, dbReadOnly)
      ' Create a reference to the TreeView Control.
      Set objTree = Me!xTree.Object
      ' Find the first employee who is a supervisor.
      rst.FindFirst "[ReportsTo] Is Null"
      ' Build the TreeView list of supervisors and their employees.
      Do Until rst.NoMatch
         ' Extract the supervisor's name.
         strText = rst![LastName] & (", " + rst![FirstName])
         ' Add a root level node to the tree for the supervisor.
         Set nodCurrent = objTree.Nodes.Add(, , "a" & rst!EmployeeID, _
            strText)
         ' Use a placeholder to save this place in the recordset.
         bk = rst.Bookmark
         ' Run a recursive procedure to add all the child nodes for
         ' employees who report to this supervisor.
         AddChildren nodCurrent, rst
         ' Return to your placeholder.
         rst.Bookmark = bk
         ' Find the next supervisor.
         rst.FindNext "[ReportsTo] Is Null"
      Loop

      ExitForm_Load:
         Exit Sub
      ErrForm_Load:
         MsgBox Err.Description, vbCritical, "Form_Load"
         Resume ExitForm_Load
      End Sub

      '==================================================================
      ' This procedure adds child nodes to the tree for all employees who
      ' report to a particular supervisor, and calls itself recursively
      ' to add child nodes for all other employees they supervise.
      '
      ' Note that this procedure accepts the open Employees recordset by
      ' reference so you do not have to open a new recordset for each
      ' call.
      '==================================================================
      Sub AddChildren(nodBoss As Node, rst As Recordset)
      On Error GoTo ErrAddChildren
      Dim nodCurrent As Node
      Dim objTree As TreeView, strText As String, bk As String

      ' Create a reference to the TreeView control.
      Set objTree = Me!xTree.Object
      ' Find the first employee who reports to the supervisor for this
      ' node.
      rst.FindFirst "[ReportsTo] =" & Mid(nodBoss.Key, 2)
      ' Build the list of employees who report to this supervisor.
      Do Until rst.NoMatch
         ' Extract the employee's name.
         strText = rst![LastName] & (", " + rst![FirstName])
         ' Add as a child node to the tree.
         Set nodCurrent = objTree.Nodes.Add(nodBoss, tvwChild, "a" & _
            rst!EmployeeID, strText)
         ' Save your place in the recordset.
         bk = rst.Bookmark
         ' Add any employees for whom the current node is a supervisor.
         AddChildren nodCurrent, rst
         ' Return to your place in the recordset and continue to search.
         rst.Bookmark = bk
         ' Find the next employee who reports to this supervisor.
         rst.FindNext "[ReportsTo]=" & Mid(nodBoss.Key, 2)
      Loop

      ExitAddChildren:
         Exit Sub
      ErrAddChildren:
         MsgBox "Can't add child:  " & Err.Description, vbCritical, _
            "AddChildren(nodBoss As Node) Error:"
         Resume ExitAddChildren
      End Sub

      '==================================================================
      'This procedure in the OLEStartDrag event of the TreeView control
      'clears the selected node so you can choose a new one.
      '==================================================================
      Private Sub xTree_OLEStartDrag(Data As Object, AllowedEffects As _
         Long)
      Me!xTree.Object.SelectedItem = Nothing
      End Sub

      '==================================================================
      'Use the OLEDragOver event of the TreeView control to select the
      'node to drag, and to highlight the target nodes where the drop will
      'occur when you release the mouse. This procedure sets the selected
      'node to drag once. After that, if a node is already selected, the
      'procedure assumes it was set during an earlier call in the dragging
      'process and it does not reset it.  The second half of this procedure
      'highlights the node you are dragging over.
      '==================================================================
      Private Sub xTree_OLEDragOver(Data As Object, Effect As Long, _
         Button As Integer, Shift As Integer, x As Single, y As Single, _
         State As Integer)
      Dim oTree As TreeView

      ' Create a reference to the TreeView control.
      Set oTree = Me!xTree.Object
      ' If no node is selected, select the first node you dragged over.
      If oTree.SelectedItem Is Nothing Then
         Set oTree.SelectedItem = oTree.HitTest(x, y)
      End If
      ' Highlight the node being dragged over as a potential drop target.
      Set oTree.DropHighlight = oTree.HitTest(x, y)
      End Sub

      '==================================================================
      'The OLEDragDrop event moves the selected node on the TreeView
      'control to its new location and changes the corresponding record in
      'the Employees table. The procedure first checks that the TreeView
      'has a selected node. If so, it continues to check if a drop target
      'node is highlighted. If no node is highlighted, then the user has
      'dragged the node off the tree and dropped it into a blank area, and
      'the procedure adds a branch to the root of the tree. If a node is
      'highlighted, the procedure modifies the Employee table's ReportTo
      'field accordingly and sets the selected node's parent property
      'to the node that has the drop highlight.
      '==================================================================
      Private Sub xTree_OLEDragDrop(Data As Object, Effect As Long, _
         Button As Integer, Shift As Integer, x As Single, y As Single)
      On Error GoTo ErrxTree_OLEDragDrop
      Dim oTree As TreeView, strKey As String, strText As String
      Dim nodNew As Node, nodDragged As Node
      Dim db As Database, rs As Recordset

      Set db = CurrentDb
      ' Open the Employees table for editing.
      Set rs = db.OpenRecordset("Employees", dbOpenDynaset)
      ' Create a reference to the TreeView control.
      Set oTree = Me!xTree.Object
      ' If nothing is selected for drag, do nothing.
      If oTree.SelectedItem Is Nothing Then
      Else
         ' Reference the selected node as the one being dragged.
         Set nodDragged = oTree.SelectedItem
         ' If the node was dragged to an empty space, update the Employees
         ' table and make this employee a root node.
         If oTree.DropHighlight Is Nothing Then
            ' Save the key and the text to use when you re-add the node.
            strKey = nodDragged.Key
            strText = nodDragged.Text
            ' Delete the current node for the employee.
            oTree.Nodes.Remove nodDragged.Index
            ' Locate the record in the Employees table and update it.
            rs.FindFirst "[EmployeeID]=" & Mid(strKey, 2)
            rs.Edit
               rs![ReportsTo] = Null
            rs.Update
            ' Add this employee as a root node.
            Set nodNew = oTree.Nodes.Add(, , strKey, strText)
            ' Add all the child nodes for this employee.
            AddChildren nodNew, rs
         ' If you are not dropping the node on itself.
         ElseIf nodDragged.Index <> oTree.DropHighlight.Index Then
            ' Set the drop target as the selected node's parent.
            Set nodDragged.Parent = oTree.DropHighlight
            ' Locate the record in the Employees table and update it.
            rs.FindFirst "[EmployeeID]=" & Mid(nodDragged.Key, 2)
            rs.Edit
               rs![ReportsTo] = Mid(oTree.DropHighlight.Key, 2)
            rs.Update
         End If
      End If
      ' Deselect the node
      Set nodDragged = Nothing
      ' Unhighlight the nodes.
      Set oTree.DropHighlight = Nothing
      ExitxTree_OLEDragDrop:
         Exit Sub
      ErrxTree_OLEDragDrop:
         ' If you create a circular branch.
         If Err.Number = 35614 Then
            MsgBox "A supervisor cannot report to a subordinate.", _
               vbCritical, "Move Cancelled"
         Else
            MsgBox "An error occurred while trying to move the node.  " & _
            "Please try again." & vbCrLf & Error.Description
         End If
         Resume ExitxTree_OLEDragDrop
      End Sub

10. On the Debug menu, click "Compile and Save All Modules."

11. Close the form's class module and switch the form to Form view.

    Practice dragging and dropping employee names in the TreeView control
    and note how both the tree and the Employees table are updated with the
    new information.

REFERENCES

For additional information about using the TreeView control, search the Help Index for "TreeView control," and see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q162523
   TITLE     : Migrating from Data Outline Control to TreeView Control

For more information about using recursion in Microsoft Access, search the Help Index for "recursive procedures."

Additional query words: DragDrop StartDrag DragOver Recursive

Keywords          : kbprg FmrCdbeh MdlRcd PgmObj 
Version           : 97
Platform          : WINDOWS
Hardware          : x86
Issue type        : kbhowto

Last Reviewed: November 21, 1998