VBA to Populate Excel Userform Treeview from MS SQL

bhalbach

Board Regular
Joined
Mar 15, 2018
Messages
221
Office Version
  1. 2016
Platform
  1. Windows
I can not seem to figure this out, can someone assist please.

I have a userfrom in excel that has a treeview, I am trying to populate the treeview with a recordset from ms sql using ADO.

I have managed to populate the Parent Nodes but have not been able to figure out how to populate the child nodes. Everything with the connection to the database and getting a recordset returned seems to be working as I do get the parent nodes to populate.

I am a rookie in vba and have been able to eventually figure things out with google and youtube, but I am stuck on this one...cant find much online related to what I am trying to do.

I have tried the following code and I get a error " Error number = 2147257114 Invalid object"

This is the first time I have tried using treeview.

All assistance would be greatly appreciated.

VBA Code:
    Me.TreeView1.Nodes.Clear
    
    'load Treeview
    Do While Not rs.EOF
    
        Me.TreeView1.Nodes.Add = rs.Fields.Item("BidItemNo")
        Me.TreeView1.Nodes.Add rs.Fields.Item("BidItemNo"), tvwChild, rs.Fields.Item("BidItemDescription"), rs.Fields.Item("BidItemDescription")

        
    rs.MoveNext
    Loop
 
I really appreciate your assistance, I am pretty new to VBA.
This is exactly the outcome i am seeking.

Not sure why, but I am only getting the 1st record populating. I even made a brand new workbook and tried it.
I've attached the recordset from my ms sql database, the stored procedure I am using to populate with and a screen shot of the userform.
Maybe you can see something I am missing.

I thought maybe the fact that the "ActivityCode" can have duplicatation through the BidItems(1 Bid Item will only have an ActivityCode once) might be doing something, so I manipulated my data so there was no duplicate and it made no difference.

VBA Code:
Sub ProcName()
Dim n As Node
Dim Conn1 As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim sql As String

    With Me.TreeView1
      .Appearance = ccFlat
      .CheckBoxes = False
      .LineStyle = tvwRootLines
      .Nodes.Clear
    End With

    Set Conn1 = New ADODB.Connection
    Set cmd = New ADODB.Command
    Set rs = New ADODB.Recordset

    Conn1.ConnectionString = SQLConStr
    Conn1.Open

    cmd.ActiveConnection = Conn1

    On Error GoTo ErrorHandler
 
    cmd.CommandType = adCmdStoredProc
    cmd.CommandText = "spGetTeeview1Data"
    cmd.Parameters.Refresh
    cmd.NamedParameters = True
    cmd.Parameters("@EstimateID").Value = Me.txtEstimateNo.Value

    Set rs = cmd.Execute
 
    Me.TreeView1.Nodes.Clear
    Me.TreeView1.Nodes.Add , , "root1", Me.txtContractTitle.Value
 
    'load Treeview
    Do While Not rs.EOF
        Set n = GetNode("n" & rs.Fields.Item("BidItemNo"))
        If n Is Nothing Then
            Set n = Me.TreeView1.Nodes.Add("root1", tvwChild, "n" & rs.Fields.Item("BidItemNo"), rs.Fields.Item("BidItemNo") & " - " & rs.Fields.Item("BidItemDescription"))
        End If
        Me.TreeView1.Nodes.Add "n" & rs.Fields.Item("BidItemNo"), tvwChild, "n" & rs.Fields.Item("ActivityCode"), rs.Fields.Item("ActivityCode") & " : " & rs.Fields.Item("ActivityDescription")
        rs.MoveNext
    Loop
 
    'Optional if you want to have all nodes expanded when the form displays
    For Each n In Me.TreeView1.Nodes
        n.Expanded = True
    Next n
 
    On Error GoTo 0

    Conn1.CommitTrans
    Conn1.Close

    Set Conn1 = Nothing
    Set rs = Nothing

    Exit Sub

ErrorHandler:

End Sub

Function GetNode(nText As String) As Node
    Dim n As Node
    For Each n In Me.TreeView1.Nodes
        If n.Key = "n" & nText Then
            Set GetNode = n
            Exit Function
        End If
    Next
    Set GetNode = Nothing
End Function

Private Sub CommandButton1_Click()

    Call ProcName

End Sub

[ATTACH type="full"]57109[/ATTACH][ATTACH type="full"]57107[/ATTACH][ATTACH type="full"]57108[/ATTACH]

I believe the issue is the keys are not unique.
When I comment out the "On Error Go To Error Handler" I get Run-time error '35602' Key is Not Unique in the collection.

I am thinking because the BidItemNo and the ActivityItemCode are not unique through the dataset. Leaning towards the ActivityItemCode causing the problem but I am not familiar enough with vba to follow your code...but im playing with it. Any help would be really great.
Since you're new to VBA, you might not be very familiar with debugging as the code is running. Look at a few online examples/tutorials (example) and use it to step through the code to see if you can follow what is happening. You can set a breakpoint on a line like the Do While line and run the code to the breakpoint, or you can just step through the code (F8) from the beginning of the code. It's not too long, so stepping through the whole thing shouldn't be too much trouble. Share what your findings are.
I know what the issue is, i did some trials and have determined that if the "ActivityCode" is not Unique the treeview will error out with Run-time error '35602' Key is not unique in collection.

The ActivityCode will repeat throughout the recordset in most cases, as well A Null may be returned in the recordset therefore the Null is not unique either.
-When an ActivityCode is not Unique in the recordset, the error will occur. ActivityCodes will repeat in the recordset multiple times.
-Null in a recordset will occur likely multiple times, if "Null" in the ActivityCode occurs more than once then the error occurs because then Null is not unique.
-Repeated ActivityDescription has no effect and it works as long as the ActivityCode is unique.
-If the ActivityCode is Null, only the BidItemNo and BidItemSecription should populate the treeview and the related ActivityCode and ActivityDescription should not be populated.

Also, I will be having more childs for the tree...for example the ActivityCode/ActivityDescription will end up being a Parent to ResourceCode/ResourceActivity. Possibly one more level as well.
BidItemNo/BidItemDescription
.........ActivityCode/ActivityDescription
.................ResourceCode/ResourceDescription
.........................NewLevelCode/NewLevelDescription

I am struggling to understand your code, so I haven't been able to make the necessary corrections...I've spent hours on this already ugh.

I tried to attach a snip of the table I was using in excel for the trial but it MrExcel says it is too large.
 
Upvote 0

Excel Facts

Select all contiguous cells
Pressing Ctrl+* (asterisk) will select the "current region" - all contiguous cells in all directions.
Can you put the data into a Google Sheets doc and share the link?

Quickly try this code to see if we've corrected the non-unique names for only the BidItems and ActivityCodes. We can add the other 2 levels later.
VBA Code:
Sub ProcName()
Dim n As Node
Dim Conn1 As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim sql As String

    With Me.TreeView1
      .Appearance = ccFlat
      .CheckBoxes = False
      .LineStyle = tvwRootLines
      .Nodes.Clear
    End With

    Set Conn1 = New ADODB.Connection
    Set cmd = New ADODB.Command
    Set rs = New ADODB.Recordset

    Conn1.ConnectionString = SQLConStr
    Conn1.Open

    cmd.ActiveConnection = Conn1

    On Error GoTo ErrorHandler
    
    cmd.CommandType = adCmdStoredProc
    cmd.CommandText = "spGetTeeview1Data"
    cmd.Parameters.Refresh
    cmd.NamedParameters = True
    cmd.Parameters("@EstimateID").Value = Me.txtEstimateNo.Value

    Set rs = cmd.Execute
   
    Me.TreeView1.Nodes.Clear
    Me.TreeView1.Nodes.Add , , "root1", Me.txtContractTitle.Value
   
    'load Treeview
    Do While Not rs.EOF
        Set n = GetNode("n" & rs.Fields.Item("BidItemNo"))
        If n Is Nothing Then
            Set n = Me.TreeView1.Nodes.Add("root1", tvwChild, "BIN" & rs.Fields.Item("BidItemNo"), rs.Fields.Item("BidItemNo") & " - " & rs.Fields.Item("BidItemDescription"))
        End If
        Me.TreeView1.Nodes.Add "BIN" & rs.Fields.Item("BidItemNo"), tvwChild, "BIN" & rs.Fields.Item("BidItemNo") & "AC" & rs.Fields.Item("ActivityCode"), rs.Fields.Item("ActivityCode") & " : " & rs.Fields.Item("ActivityDescription")
        rs.MoveNext
    Loop
   
    'Optional if you want to have all nodes expanded when the form displays
    For Each n In Me.TreeView1.Nodes
        n.Expanded = True
    Next n
    
    On Error GoTo 0

    Conn1.CommitTrans
    Conn1.Close

    Set Conn1 = Nothing
    Set rs = Nothing

    Exit Sub

ErrorHandler:

End Sub

Function GetNode(nText As String) As Node
    Dim n As Node
    For Each n In Me.TreeView1.Nodes
        If n.Key = "n" & nText Then
            Set GetNode = n
            Exit Function
        End If
    Next
    Set GetNode = Nothing
End Function

Private Sub CommandButton1_Click()

    Call ProcName

End Sub
 
Upvote 0
Can you put the data into a Google Sheets doc and share the link?

Quickly try this code to see if we've corrected the non-unique names for only the BidItems and ActivityCodes. We can add the other 2 levels later.
VBA Code:
Sub ProcName()
Dim n As Node
Dim Conn1 As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim sql As String

    With Me.TreeView1
      .Appearance = ccFlat
      .CheckBoxes = False
      .LineStyle = tvwRootLines
      .Nodes.Clear
    End With

    Set Conn1 = New ADODB.Connection
    Set cmd = New ADODB.Command
    Set rs = New ADODB.Recordset

    Conn1.ConnectionString = SQLConStr
    Conn1.Open

    cmd.ActiveConnection = Conn1

    On Error GoTo ErrorHandler
   
    cmd.CommandType = adCmdStoredProc
    cmd.CommandText = "spGetTeeview1Data"
    cmd.Parameters.Refresh
    cmd.NamedParameters = True
    cmd.Parameters("@EstimateID").Value = Me.txtEstimateNo.Value

    Set rs = cmd.Execute
  
    Me.TreeView1.Nodes.Clear
    Me.TreeView1.Nodes.Add , , "root1", Me.txtContractTitle.Value
  
    'load Treeview
    Do While Not rs.EOF
        Set n = GetNode("n" & rs.Fields.Item("BidItemNo"))
        If n Is Nothing Then
            Set n = Me.TreeView1.Nodes.Add("root1", tvwChild, "BIN" & rs.Fields.Item("BidItemNo"), rs.Fields.Item("BidItemNo") & " - " & rs.Fields.Item("BidItemDescription"))
        End If
        Me.TreeView1.Nodes.Add "BIN" & rs.Fields.Item("BidItemNo"), tvwChild, "BIN" & rs.Fields.Item("BidItemNo") & "AC" & rs.Fields.Item("ActivityCode"), rs.Fields.Item("ActivityCode") & " : " & rs.Fields.Item("ActivityDescription")
        rs.MoveNext
    Loop
  
    'Optional if you want to have all nodes expanded when the form displays
    For Each n In Me.TreeView1.Nodes
        n.Expanded = True
    Next n
   
    On Error GoTo 0

    Conn1.CommitTrans
    Conn1.Close

    Set Conn1 = Nothing
    Set rs = Nothing

    Exit Sub

ErrorHandler:

End Sub

Function GetNode(nText As String) As Node
    Dim n As Node
    For Each n In Me.TreeView1.Nodes
        If n.Key = "n" & nText Then
            Set GetNode = n
            Exit Function
        End If
    Next
    Set GetNode = Nothing
End Function

Private Sub CommandButton1_Click()

    Call ProcName

End Sub

I am getting the same thing with this code.

Below is a dropbox link to the excel file.
I made 2 userforms in it...
Userform1 i tried this code that gets the recordset from the database with stored procedure. The data that the stored procedure generates in on sheet named Form1.
Userform 2 is the code that you made getting the data from a worksheet. Sheet Form2 uses that code. It works if I do not have duplicates in the ActivityCode

Let me know if this link works to access the excel file...I dont share much so I had to try and remember how.


 
Upvote 0
The file came through okay.

Here is the code for UserForm1. It has the Resource and NewLevel code commented out. If all works with Activity, you can un-comment to see if they work as well. I'm not sure what the value of the NULL fields actually are. Are they nullstrings ("")? Are they actual NULL characters? There is an If test to see if after setting the nodeText string if it is simply " : ", which should be the case if the Nulls don't return anything. Check this to see if that is the way to detect Nulls.

I also added the extra "key" strings, which add more code, but when stepping through in debug mode, can be helpful to see if the right data is added. Plus, the code for adding the child node is a little cleaner.

The key (pun intended (groan)) to creating unique key values in this code is to make sure to concatenate all the numbers (BidItemNo, ActivityCode, etc.) together. This should create a unique value for each key. Even though, for example, an activity code is the same as in another bid, since the bid is different, the concatenated key string will be different.
VBA Code:
Option Explicit
'Home
'Const SQLConStr As String = "Provider=SQLOLEDB; Data Source=DESKTOP-DNAANVC; Initial Catalog=brentApp; uid=sa; pwd=Biff1972"
'Work
Const SQLConStr As String = "Provider=SQLOLEDB; Data Source=LAPTOP-02; Initial Catalog=brentApp; uid=sa; pwd=Biff1972"

Sub ProcName()
Dim n As Node
Dim Conn1 As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim sql As String
Dim keyBidItem As String
Dim keyActivity As String
Dim keyResource As String
Dim keyNewlevel As String
Dim nodeText As String

    With Me.TreeView1
      .Appearance = ccFlat
      .CheckBoxes = False
      .LineStyle = tvwRootLines
      .Nodes.Clear
    End With

    Set Conn1 = New ADODB.Connection
    Set cmd = New ADODB.Command
    Set rs = New ADODB.Recordset

    Conn1.ConnectionString = SQLConStr
    Conn1.Open

    cmd.ActiveConnection = Conn1

    'On Error GoTo ErrorHandler
    
    cmd.CommandType = adCmdStoredProc
    cmd.CommandText = "spGetTeeviewData"
    cmd.Parameters.Refresh
    cmd.NamedParameters = True
    cmd.Parameters("@EstimateID").Value = Me.txtEstimateNo.Value

    Set rs = cmd.Execute
   
    Me.TreeView1.Nodes.Clear
    Me.TreeView1.Nodes.Add , , "root1", Me.txtContractTitle.Value
   
    'load Treeview
    Do While Not rs.EOF
        keyBidItem = "BIN" & rs.Fields.Item("BidItemNo")
        nodeText = rs.Fields.Item("BidItemNo") & " - " & rs.Fields.Item("BidItemDescription")
        If Not NodeExists(keyBidItem) Then
            Me.TreeView1.Nodes.Add "root1", tvwChild, keyBidItem, nodeText
        End If
        
        keyActivity = keyBidItem & "AC" & rs.Fields.Item("ActivityCode")
        nodeText = rs.Fields.Item("ActivityCode") & " : " & rs.Fields.Item("ActivityDescription")
        'Check for null
        If nodeText <> " : " Then
            Me.TreeView1.Nodes.Add keyBidItem, tvwChild, keyActivity, nodeText
        End If
        
'        keyResource = keyActivity & "RC" & rs.Fields.Item("ResourceCode")
'        nodeText = rs.Fields.Item("ResourceCode") & " : " & rs.Fields.Item("ResourceDescription")
'        If nodeText <> " : " Then
'        Me.TreeView1.Nodes.Add keyActivity, tvwChild, keyResource, nodeText
'        End If
'
'        keyNewlevel = keyResource & "NLC" & rs.Fields.Item("NewLevelCode")
'        nodeText = rs.Fields.Item("NewLevelCode") & " : " & rs.Fields.Item("NewLevelDescription")
'        If nodeText <> " : " Then
'        Me.TreeView1.Nodes.Add keyResource, tvwChild, keyNewlevel, nodeText
'        End If
        
        rs.MoveNext
    Loop
   
    'Optional if you want to have all nodes expanded when the form displays
    For Each n In Me.TreeView1.Nodes
        n.Expanded = True
    Next n
    
    On Error GoTo 0

    Conn1.CommitTrans
    Conn1.Close

    Set Conn1 = Nothing
    Set rs = Nothing

    Exit Sub

ErrorHandler:

End Sub

Function NodeExists(nText As String) As Boolean
    Dim n As Node
    For Each n In Me.TreeView1.Nodes
        If InStr(1, n.Key, nText) > 0 Then
            NodeExists = True
            Exit Function
        End If
    Next
    NodeExists = False
End Function

Private Sub CommandButton1_Click()

    Call ProcName

End Sub
Here is UserForm2 code:
VBA Code:
Option Explicit

Private Sub UserForm_Initialize()
    Dim c As Range
    Dim n As Node
    Dim keyBidItem As String
    Dim keyActivity As String
    Dim keyResource As String
    Dim keyNewlevel As String
   
    Me.TreeView1.Nodes.Clear
    Me.TreeView1.Nodes.Add , , "root1", "Contract Title"
    For Each c In Range("A2:A23")
        keyBidItem = "BIN" & c.Value
        If Not NodeExists(keyBidItem) Then
            Me.TreeView1.Nodes.Add "root1", tvwChild, keyBidItem, c.Value & " - " & c.Offset(0, 1).Value
        End If
        keyActivity = keyBidItem & "AC" & c.Offset(0, 2)
        Me.TreeView1.Nodes.Add keyBidItem, tvwChild, keyActivity, c.Offset(0, 2) & " : " & c.Offset(0, 3)
    Next c
    For Each n In Me.TreeView1.Nodes
        n.Expanded = True
    Next n
End Sub

Function NodeExists(nText As String) As Boolean
    Dim n As Node
    For Each n In Me.TreeView1.Nodes
        If InStr(1, n.Key, nText) > 0 Then
            NodeExists = True
            Exit Function
        End If
    Next
    NodeExists = False
End Function
 
Upvote 0
The file came through okay.

Here is the code for UserForm1. It has the Resource and NewLevel code commented out. If all works with Activity, you can un-comment to see if they work as well. I'm not sure what the value of the NULL fields actually are. Are they nullstrings ("")? Are they actual NULL characters? There is an If test to see if after setting the nodeText string if it is simply " : ", which should be the case if the Nulls don't return anything. Check this to see if that is the way to detect Nulls.

I also added the extra "key" strings, which add more code, but when stepping through in debug mode, can be helpful to see if the right data is added. Plus, the code for adding the child node is a little cleaner.

The key (pun intended (groan)) to creating unique key values in this code is to make sure to concatenate all the numbers (BidItemNo, ActivityCode, etc.) together. This should create a unique value for each key. Even though, for example, an activity code is the same as in another bid, since the bid is different, the concatenated key string will be different.
VBA Code:
Option Explicit
'Home
'Const SQLConStr As String = "Provider=SQLOLEDB; Data Source=DESKTOP-DNAANVC; Initial Catalog=brentApp; uid=sa; pwd=Biff1972"
'Work
Const SQLConStr As String = "Provider=SQLOLEDB; Data Source=LAPTOP-02; Initial Catalog=brentApp; uid=sa; pwd=Biff1972"

Sub ProcName()
Dim n As Node
Dim Conn1 As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim sql As String
Dim keyBidItem As String
Dim keyActivity As String
Dim keyResource As String
Dim keyNewlevel As String
Dim nodeText As String

    With Me.TreeView1
      .Appearance = ccFlat
      .CheckBoxes = False
      .LineStyle = tvwRootLines
      .Nodes.Clear
    End With

    Set Conn1 = New ADODB.Connection
    Set cmd = New ADODB.Command
    Set rs = New ADODB.Recordset

    Conn1.ConnectionString = SQLConStr
    Conn1.Open

    cmd.ActiveConnection = Conn1

    'On Error GoTo ErrorHandler
 
    cmd.CommandType = adCmdStoredProc
    cmd.CommandText = "spGetTeeviewData"
    cmd.Parameters.Refresh
    cmd.NamedParameters = True
    cmd.Parameters("@EstimateID").Value = Me.txtEstimateNo.Value

    Set rs = cmd.Execute
 
    Me.TreeView1.Nodes.Clear
    Me.TreeView1.Nodes.Add , , "root1", Me.txtContractTitle.Value
 
    'load Treeview
    Do While Not rs.EOF
        keyBidItem = "BIN" & rs.Fields.Item("BidItemNo")
        nodeText = rs.Fields.Item("BidItemNo") & " - " & rs.Fields.Item("BidItemDescription")
        If Not NodeExists(keyBidItem) Then
            Me.TreeView1.Nodes.Add "root1", tvwChild, keyBidItem, nodeText
        End If
     
        keyActivity = keyBidItem & "AC" & rs.Fields.Item("ActivityCode")
        nodeText = rs.Fields.Item("ActivityCode") & " : " & rs.Fields.Item("ActivityDescription")
        'Check for null
        If nodeText <> " : " Then
            Me.TreeView1.Nodes.Add keyBidItem, tvwChild, keyActivity, nodeText
        End If
     
'        keyResource = keyActivity & "RC" & rs.Fields.Item("ResourceCode")
'        nodeText = rs.Fields.Item("ResourceCode") & " : " & rs.Fields.Item("ResourceDescription")
'        If nodeText <> " : " Then
'        Me.TreeView1.Nodes.Add keyActivity, tvwChild, keyResource, nodeText
'        End If
'
'        keyNewlevel = keyResource & "NLC" & rs.Fields.Item("NewLevelCode")
'        nodeText = rs.Fields.Item("NewLevelCode") & " : " & rs.Fields.Item("NewLevelDescription")
'        If nodeText <> " : " Then
'        Me.TreeView1.Nodes.Add keyResource, tvwChild, keyNewlevel, nodeText
'        End If
     
        rs.MoveNext
    Loop
 
    'Optional if you want to have all nodes expanded when the form displays
    For Each n In Me.TreeView1.Nodes
        n.Expanded = True
    Next n
 
    On Error GoTo 0

    Conn1.CommitTrans
    Conn1.Close

    Set Conn1 = Nothing
    Set rs = Nothing

    Exit Sub

ErrorHandler:

End Sub

Function NodeExists(nText As String) As Boolean
    Dim n As Node
    For Each n In Me.TreeView1.Nodes
        If InStr(1, n.Key, nText) > 0 Then
            NodeExists = True
            Exit Function
        End If
    Next
    NodeExists = False
End Function

Private Sub CommandButton1_Click()

    Call ProcName

End Sub
Here is UserForm2 code:
VBA Code:
Option Explicit

Private Sub UserForm_Initialize()
    Dim c As Range
    Dim n As Node
    Dim keyBidItem As String
    Dim keyActivity As String
    Dim keyResource As String
    Dim keyNewlevel As String
 
    Me.TreeView1.Nodes.Clear
    Me.TreeView1.Nodes.Add , , "root1", "Contract Title"
    For Each c In Range("A2:A23")
        keyBidItem = "BIN" & c.Value
        If Not NodeExists(keyBidItem) Then
            Me.TreeView1.Nodes.Add "root1", tvwChild, keyBidItem, c.Value & " - " & c.Offset(0, 1).Value
        End If
        keyActivity = keyBidItem & "AC" & c.Offset(0, 2)
        Me.TreeView1.Nodes.Add keyBidItem, tvwChild, keyActivity, c.Offset(0, 2) & " : " & c.Offset(0, 3)
    Next c
    For Each n In Me.TreeView1.Nodes
        n.Expanded = True
    Next n
End Sub

Function NodeExists(nText As String) As Boolean
    Dim n As Node
    For Each n In Me.TreeView1.Nodes
        If InStr(1, n.Key, nText) > 0 Then
            NodeExists = True
            Exit Function
        End If
    Next
    NodeExists = False
End Function

AWESOME..............Seems to work exactly as I envisioned it...Ill play with it some with NULLS and other things to see if it runs through the code without issue. I have spent a ton of time googling and youtube trying to figure this out. Now I need to try and understand your code. Thank you so much.

The NULL is what is visible in the database table, I'm not sure how this actually comes in the dataset...I'm new to ADO and SQL as well.

Does the treeview have properties to set the amount of indentation on the Parent/Child nodes? I'm pretty tight on available space in what I am building.

How would I identify which node I am on so I can populate a textbox/label from the clicked node to populate other stuff on the userform.
-What I need it to do is if it is at the first level (BidItem) then I want to isolate out the BidItemCode to populate TextBox35 and the BidItemDescription to populate Label163
-What I need it to do is if it is at the second level (ActivityItem) then I want to isolate out the ActivityItemCode to populate TextBox49 and the BidItemDescription to populate textBox48
I have been reading on this, I know I will have to pick out the characters I want from the concatenated BidItemCode/BidItemDescription and the concatenated ActivityItemCode/ActivityItemDescription but I haven't found anything that would guide me on a direction for getting the proper data to the proper textbox/label.
Weird I know...concatenate the values and then pick out the characters that were concatenated :)
Some simple code I have been playing with but doesnt give me what Im needing.

VBA Code:
Private Sub TreeView1_NodeClick(ByVal Node As MSComctlLib.Node)

With Me
    .TextBox35.Text = Node.Text
    .TextBox48.Text = Mid(Node.Child.Text, 16, 150)
    .TextBox49.Text = Mid(Node.Child.Text, 10, 4)
End With

End Sub
 
Upvote 0
Does the treeview have properties to set the amount of indentation on the Parent/Child nodes?
Yes. There is an "Indentation" property that sets this. You can change it in the properties of the TreeView during the design phase, or in the code at run-time. In the value for the file you sent, the size is 28.35. Changing it to 5 or so shortens it up a bit. Alternatively, you could use the UserForm_Initialize procedure and add something like "TreeView1.Indentation = 5".

How would I identify which node I am on so I can populate a textbox/label from the clicked node to populate other stuff on the userform.
This code should be added to the Userform's code section as well.
VBA Code:
Private Sub TreeView1_NodeClick(ByVal Node As MSComctlLib.Node)
    Dim sCode As String
    Dim sDesc As String
    Dim a As Variant
    
    a = Split(Node.Text, " : ")  'Creates array based on " : " as the separation string. Since the node text should only have one of them, a 2 item array should be formed
    Select Case NodeLevel(Node)
        Case 1  'Node is at BidItem level, so populate BitItem objects
            TextBox35.Text = a(0)
            Label163.Caption = a(1)
        Case 2  'Node is at Activity level, so populate Activity objects
            TextBox49.Text = a(0)
            TextBox48.Caption = a(1)
    End Select
End Sub

Private Function NodeLevel(Node As MSComctlLib.Node) As Integer
    Dim withoutSlashes As Integer
    Dim withSlashes As Integer
    
    withSlashes = Len(Node.FullPath)
    withoutSlashes = Len(Replace(Node.FullPath, "\", ""))
    NodeLevel = withSlashes - withoutSlashes
End Function
 
Upvote 0
Yes. There is an "Indentation" property that sets this. You can change it in the properties of the TreeView during the design phase, or in the code at run-time. In the value for the file you sent, the size is 28.35. Changing it to 5 or so shortens it up a bit. Alternatively, you could use the UserForm_Initialize procedure and add something like "TreeView1.Indentation = 5".


This code should be added to the Userform's code section as well.
VBA Code:
Private Sub TreeView1_NodeClick(ByVal Node As MSComctlLib.Node)
    Dim sCode As String
    Dim sDesc As String
    Dim a As Variant
  
    a = Split(Node.Text, " : ")  'Creates array based on " : " as the separation string. Since the node text should only have one of them, a 2 item array should be formed
    Select Case NodeLevel(Node)
        Case 1  'Node is at BidItem level, so populate BitItem objects
            TextBox35.Text = a(0)
            Label163.Caption = a(1)
        Case 2  'Node is at Activity level, so populate Activity objects
            TextBox49.Text = a(0)
            TextBox48.Caption = a(1)
    End Select
End Sub

Private Function NodeLevel(Node As MSComctlLib.Node) As Integer
    Dim withoutSlashes As Integer
    Dim withSlashes As Integer
  
    withSlashes = Len(Node.FullPath)
    withoutSlashes = Len(Replace(Node.FullPath, "\", ""))
    NodeLevel = withSlashes - withoutSlashes
End Function
Works pretty slick.
Except I gave you some incomplete information.
I did not think it through entirely, and some other fields can be populated all at the same time from the same recordset.
Really sorry about that.

The above code works as I explained it except Label163 has Run-time error '9': Script Out of Range. I tried using a new textbox for this line and changed the code to the TextBox51.Text and it did the same thing.

The incomplete information I gave you...
-If the Node that is Selected is a BidItem then Textbox35 is to populate with BidItemCode and Label163 is to populate with BidItemDescription. ActivityCode is to be blank and ActivityItemDescription is to be Blank. There are also other fields that I can have in the same recordset that can populate at the same time...Label164 is to populate with TakeOffQuantity, Label165 is to populate with BidItemUOM, Label168 populate with BidItemQuantity

-If the Node that is selected is an ActivityItem then Textbox35 is to populate with the BidItemCode of its Parent and Label163 is to populate with BidItemDescription of its Parent...AND TextBox49 is to populate with the selected Node ActivityItemCode and Textbox48 is to populate with the selected Node ActivityItemDescription. There are also other fields that I can have in the same recordset that can populate at the same time...TextBox47 is to populate with ActivityItemQuantity, textBox46 is to populate with ActivityItemUOM

I think I explained this correctly.
 
Last edited:
Upvote 0
Sorry. The subscript out of range was because I had that both nodes had colons, but only ActivityCode does. BidItem has a hyphen. This also updates the population information you provided.
VBA Code:
Private Sub TreeView1_NodeClick(ByVal Node As MSComctlLib.Node)
    Dim sCode As String
    Dim sDesc As String
    Dim a As Variant
    
    Select Case NodeLevel(Node)
        Case 1  'Node is at BidItem level, so populate BitItem objects
            a = Split(Node.Text, " - ")  'Creates array based on " : " as the separation string. Since the node text should only have one of them, a 2 item array should be formed
            TextBox35.Text = a(0)
            Label163.Caption = a(1)
            TextBox49.Text = ""
            TextBox48.Text = ""
        Case 2  'Node is at Activity level, so populate Activity objects
            a = Split(Node.Text, " : ")  'Creates array based on " : " as the separation string. Since the node text should only have one of them, a 2 item array should be formed
            TextBox49.Text = a(0)
            TextBox48.Text = a(1)
            a = Split(Node.Parent.Text, " - ")
            TextBox35.Text = a(0)
            Label163.Caption = a(1)
    End Select
End Sub
 
Upvote 0
Sorry. The subscript out of range was because I had that both nodes had colons, but only ActivityCode does. BidItem has a hyphen. This also updates the population information you provided.
VBA Code:
Private Sub TreeView1_NodeClick(ByVal Node As MSComctlLib.Node)
    Dim sCode As String
    Dim sDesc As String
    Dim a As Variant
  
    Select Case NodeLevel(Node)
        Case 1  'Node is at BidItem level, so populate BitItem objects
            a = Split(Node.Text, " - ")  'Creates array based on " : " as the separation string. Since the node text should only have one of them, a 2 item array should be formed
            TextBox35.Text = a(0)
            Label163.Caption = a(1)
            TextBox49.Text = ""
            TextBox48.Text = ""
        Case 2  'Node is at Activity level, so populate Activity objects
            a = Split(Node.Text, " : ")  'Creates array based on " : " as the separation string. Since the node text should only have one of them, a 2 item array should be formed
            TextBox49.Text = a(0)
            TextBox48.Text = a(1)
            a = Split(Node.Parent.Text, " - ")
            TextBox35.Text = a(0)
            Label163.Caption = a(1)
    End Select
End Sub

Hmm…I referenced a recordset, but this was for
Sorry. The subscript out of range was because I had that both nodes had colons, but only ActivityCode does. BidItem has a hyphen. This also updates the population information you provided.
VBA Code:
Private Sub TreeView1_NodeClick(ByVal Node As MSComctlLib.Node)
    Dim sCode As String
    Dim sDesc As String
    Dim a As Variant
   
    Select Case NodeLevel(Node)
        Case 1  'Node is at BidItem level, so populate BitItem objects
            a = Split(Node.Text, " - ")  'Creates array based on " : " as the separation string. Since the node text should only have one of them, a 2 item array should be formed
            TextBox35.Text = a(0)
            Label163.Caption = a(1)
            TextBox49.Text = ""
            TextBox48.Text = ""
        Case 2  'Node is at Activity level, so populate Activity objects
            a = Split(Node.Text, " : ")  'Creates array based on " : " as the separation string. Since the node text should only have one of them, a 2 item array should be formed
            TextBox49.Text = a(0)
            TextBox48.Text = a(1)
            a = Split(Node.Parent.Text, " - ")
            TextBox35.Text = a(0)
            Label163.Caption = a(1)
    End Select
End Sub

Works like it should awesome.

I had mentioned Recordset in the last message and then I thought about it a bit....the recordset was related to populating the treeview. At this point does the recordset still exist or is it gone when the Sub Procedure to populate the treeview was completed? If it still exists, there are other fields that could be populate when the node is clicked.
 
Upvote 0
Yes, it still exists. If you want to populate other information if you didn't grab it the first time through while populating the treeview, you'll have to go back in and get it every time unless you can find a way to store it somewhere.
 
Upvote 0

Forum statistics

Threads
1,224,820
Messages
6,181,161
Members
453,021
Latest member
Justyna P

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top