Tree View and Ribbon Structure

KitaYama

Well-known member
Local time
Tomorrow, 07:15
Joined
Jan 6, 2022
Messages
2,046
I had a suggestion to use @MajP's Tree view class to show the structure of my custom ribbon in this old post, which I did at the time.

But, recently because of a change in my tables structure, I had to rebuild the necessary queries for his class. Though the tree itself is showing and I have not any error in the tree itself, but I've lost the possibility of saving the nodes after drag and drop.

To keep everything as simple as possible, I've copied tables and queries to his v18 tree view and have attached it here.
The ribbon items have been changed with a function using random keywords to change them from local language to English, so they are meaningless.

My main question:
I've read his hierarchical and tree view post, but still can't understand how t_E2E table should be filled.
This, causes to a fail in qryNodeE2E and raising 35613 in reLoadE2E procedure.

Any kind of help is much appreciated.
 

Attachments

Last edited:
I would take a look at the Item Genie code since you will have to do something similar.
When you move something you have to reassign the parent id in code. There is no "bound" tree.
Code:
Private Sub tvw_TreeviewNodeDragDrop(DragPK As Variant, DropPK As Variant, DragNode As MSComctlLib.Node, DropNode As MSComctlLib.Node)
  'Demonstrates drag and drop
  Dim strSql As String
  Dim DragNodeIdentifier
  Dim DropNodeIdentifier
  Dim DroppedOnRoot As Boolean
 
  DragNodeIdentifier = DragNode.Tag
  DropNodeIdentifier = DropNode.Tag
  DroppedOnRoot = (DragNode.Key = DropNode.Key)
  'If drag node = drop node it is dropped on a root
 
'Location can only be dropped on other locations not on Items
If DragNodeIdentifier = "Location_" Then
  'Make it a root node 
  If DropNode.Key = DragNode.Key Then
      strSql = "Update tblLocations set parent_iD = NULL where Location_ID = " & DragPK
    ElseIf DropNodeIdentifier = "Location_" Then
      strSql = "Update tblLocations set parent_iD = " & DropPK & " where Location_ID = " & DragPK
    ElseIf DropNodeIdentifier = "Item_" Then
      Dim parentLocationID As Long
      parentLocationID = GetNewParentPK(DropNode.Key)
      strSql = "Update tblLocations set parent_iD = " & parentLocationID & " where Location_ID = " & DragPK
      MsgBox "You dropped on an Item and not a location.  Need to figure out how to handle this, and it may not be easy. So Reloading, and moving it to a location"
      reLoadTreeview
    End If
'Items can be dropped under Locations but not under other Identifiers 
ElseIf DragNodeIdentifier = "Item_" Then
    If DropNodeIdentifier = "Location_" Then
      strSql = "Update tblItems set Location_iD_FK = " & DropPK & " where Item_ID = " & DragPK
    ElseIf DroppedOnRoot Then
      strSql = "Update tblItems set Location_iD_FK = Null where Item_ID = " & DragPK
    ElseIf DropNodeIdentifier = "Item_" Then
       MsgBox "You dropped an item onto an item. This will not persist. You need to move it under a location. It will move it to the drop node's parent.", vbCritical, "Must Put under Location"
       Dim ParentLocationKey As String
       ParentLocationKey = "Location_" & GetParentPK(tvw.getNodePK(DropNode), "Item_")
       tvw.MoveNodeByKey DragNode.Key, ParentLocationKey
    End If
  End If
 
If strSql <> "" Then CurrentDb.Execute strSql
End Sub
If you drop a node on to a new "viable" location then you have to do an update query. The drag nodes parent ID becomes the drop node.

Like the above case it gets more complicated. You can only drop your nodes under the appropriate level. You cannot drop a Tab under a control, or group. You cannot drop a ribbon under a control, Etc.
You have to do an if check to determine if the node is dropped under a viable parent node.
Unfortunately you cannot stop the drag and drop. So if it you drop it on an improper level then the above code moves it back to where it came from, forcing you to drop on the appropriate level.

Similarly you can move things around in the tree and have the sort order persist. Then you use the tree to move nodes up and down within a level. This is far easier for sorting then doing it manually.
When the form closes updated the sort order in your tables. Something like this.
Code:
Public Sub UpdateSortAndLevel()
    On Error GoTo UpdateSortAndLevel_Error
  Dim i As Variant
  Dim strSql As String
  Dim nd As Node
  Dim Identifier As String
  Dim Level As Integer
  Dim PK As Long
  For Each nd In tvw.TreeView.Nodes
    i = i + 1
    Identifier = tvw.getNodeIdentifier(nd)
    Level = tvw.GetNodeLevel(nd)
    PK = CLng(tvw.getNodePK(nd))
  '  Debug.Print "Key " & nd.key & " PK " & PK
   If Identifier = "Location_" Then
      strSql = "UPDATE tblLocations Set TreeSort = " & i & ", NodeLevel = " & Level & " where Location_ID = " & PK
   ElseIf Identifier = "Item_" Then
      strSql = "UPDATE tblItems Set TreeSort = " & i & ", NodeLevel = " & Level & " where Item_ID = " & PK
   End If
  ' Debug.Print strSql
   If strSql <> "" Then
     CurrentDb.Execute strSql, dbFailOnError
   End If
 Next nd

Reading from top of tree down the first node is 1 the last node gets a sort order of N (where n is number of nodes)

I also recommend you add the NodeLevel field to all of your tables in the tree. This will allow you then to make a pseudo tree display in forms, reports.
The form shown is a standard form using the sort order and level to make it appear as a tree and allow the color formatting.
 
I have to read carefully and digest your post carefully.
Give me a few hours please.
Thanks for your help.
 
Here is a demo you have to complete.

Code:
Private Sub tvw_TreeviewNodeDragDrop(DragPK As Variant, DropPK As Variant, DragNode As MSComctlLib.Node, DropNode As MSComctlLib.Node)
  'Demonstrates drag and drop

'Ribbon
'RibbonTab
'RibbonGroup
'RibbonControl
  Dim DragNodeIdentifier As String
  Dim DropNodeIdentifier As String
  Dim NodeText As String
  Dim nodekey As String
  Dim OriginalParentKey As String
  Dim strSql As String
  DragNodeIdentifier = tvw.getNodeIdentifier(DragNode)
  DropNodeIdentifier = tvw.getNodeIdentifier(DropNode)
  'MsgBox DragNodeIdentifier
  Select Case DragNodeIdentifier
    
    Case "Ribbon"
     If DropNodeIdentifier <> "Ribbon" Then
       MsgBox "Cannot drop a ribbon under another node"
       'This is harder then other nodes to add to the root must delete and re add the node
       nodekey = DragNode.key
       NodeText = DragNode.Text
       'Delete moved node and move it back by adding new to root.
       tvw.Nodes.Remove (DragNode.key)
       tvw.Nodes.Add , , nodekey, NodeText
     End If
      
     'can only drop a tab under the Ribbon
     Case "RibbonTab"
     If DropNodeIdentifier <> "Ribbon" Then
       MsgBox "Can only drop a Tab under a Ribbon"
       'move back to original parent that ID is in the table
       OriginalParentKey = GetOriginalParentKey(DragNode.key)
       tvw.MoveNodeByKey DragNode.key, OriginalParentKey
     Else
       'I cannot test it here but if you are going to have multiple ribbons you need to do an update query here
       'assign the current RibbonTab RibbonFK to the new RibbonFk
     End If
    
     Case "RibbonGroup"
     If DropNodeIdentifier <> "RibbonTab" Then
       MsgBox "Can only drop a RibbonGroup under a RibbonTab"
       'move back to original parent that ID is in the table
       OriginalParentKey = GetOriginalParentKey(DragNode.key)
       tvw.MoveNodeByKey DragNode.key, OriginalParentKey
     Else
       'Update to new parent
       strSql = "Update tblRibbonGroups Set tabFK = " & DropPK & " Where RibbonGroupsPK = " & DragPK
     End If
    
     Case "RibbonControl"
  
   End Select
 
  If strSql <> "" Then CurrentDb.Execute strSql
End Sub

I provided an updated version of the TreeviewForm class that has some new methods. Added a GetPriorParentKey function to help move nodes back to where they came.

If you add the following fields "TreeSort" and "NodeLevel" to each table and include the TreeSort in the Union query then you can sort nodes the way you like them to appear and persist that in the table. No longer do you have to enter the sort order
Code:
Public Sub autolevel()
  Dim i As Variant
  Dim strSql As String
  Dim nd As Node
  Dim Identifier As String
  Dim Level As Integer
  Dim PK As Long
  For Each nd In tvw.TreeView.Nodes
    i = i + 1
    Identifier = tvw.getNodeIdentifier(nd)
    Level = tvw.GetNodeLevel(nd)
    PK = CLng(tvw.getNodePK(nd))
  Select Case Identifier
   'Ribbon
   'RibbonTab
   'RibbonGroup
   'RibbonControl
   Case "Ribbon"
   Case "RibbonTab"
     strSql = "UPDATE tblRibbonTabs Set TreeSort = " & i & ", NodeLevel = " & Level & " where RibbonTabsPk = " & PK
   Case "RibbonGroup"
  
   Case "RibbonControl"
  
  End Select
 
  If strSql <> "" Then
     CurrentDb.Execute strSql, dbFailOnError
   End If
 Next nd
End Sub

You can try to drop things on the wrong level (you have to finish controls) they will move back to proper level. Groups demos the update to the new parent.

If you want to persist the tree sort order in the tables you have to add the fields and complete this.
Code:
Public Sub autolevel()
  Dim i As Variant
  Dim strSql As String
  Dim nd As Node
  Dim Identifier As String
  Dim Level As Integer
  Dim PK As Long
  For Each nd In tvw.TreeView.Nodes
    i = i + 1
    Identifier = tvw.getNodeIdentifier(nd)
    Level = tvw.GetNodeLevel(nd)
    PK = CLng(tvw.getNodePK(nd))
  Select Case Identifier
   'Ribbon
   'RibbonTab
   'RibbonGroup
   'RibbonControl
   Case "Ribbon"
   Case "RibbonTab"
     strSql = "UPDATE tblRibbonTabs Set TreeSort = " & i & ", NodeLevel = " & Level & " where RibbonTabsPk = " & PK
   Case "RibbonGroup"
  
   Case "RibbonControl"
  
  End Select
 
  If strSql <> "" Then
     CurrentDb.Execute strSql, dbFailOnError
   End If
 Next nd
End Sub
 

Attachments

Million thanks. I think I can work on it.
I'm still studying your Genie database. It's impressive.

Thanks again.
 

Users who are viewing this thread

Back
Top Bottom