TreeView. Odwzorowanie układu drzewa z danych z arkusza.   strona główna:
A po co ten Excel ;-)
 
   Nie wiem czy będzie to komuś kiedyś potrzebne jednak mi się temat podobał a że kontrolki TreeView używa się raczej dość rzadko  
im więcej przykładów jej obsługi będzie w sieci tym łatwiej będzie ją pojąć i wykorzystać do własnych celów.  
   Naszym zadaniem jest więc odwzorowanie układu drzewa kontrolki TreeView z danych w Arkuszu. Dane wyglądają np.: tak..  
 
a  a1   a1b   a1b1  
a  a1   a1b  
a  a2   a2z
 
a  a2   a2g   a2gz  
b  b1  
b  b2   b2h   b2hd  
c  a1   a1b   a1b1  
c  a1   a1b  
 
Taką oto strukturę należy odwzorować. A więc: 3 "gałęzie" główne, a od nich odpowiednio  
cała konstrukcja. Słowem całość ma wyglądać jak na obrazku.  
Ok. :-) To najpierw procedura, później tłumaczenie co i jak..  
 
 
Option Explicit  
 
Private Sub UserForm_Initialize()  
    Dim xlWks As Excel.Worksheet  
    Dim i As Long, j As Integer  
    Dim strText As String  
    Dim iCell As Integer  
    Dim strNodKey As String, strParentNodKey As String  
     
    Set xlWks = ThisWorkbook.Worksheets("Arkusz1")  
 
    With Me.TreeView1  
        .Nodes.Clear  
        On Error Resume Next  
 
        Do  
            i = i + 1  
            Do  
                j = j + 1  
                strText = xlWks.Cells(i, j)  
                If Len(strText) > 0 Then  
                    If j = 1 Then  
                        .Nodes.Add Key:=strText, _  
                                   Text:=strText  
                    Else  
                        With xlWks  
                            For iCell = 1 To j  
                                strNodKey = strNodKey & .Cells(i, iCell).Value  
                            Next  
                        End With  
                        strParentNodKey = Left(strNodKey, Len(strNodKey) - Len(strText))  
                         
                        .Nodes.Add relative:=strParentNodKey, _  
                                   relationship:=tvwChild, _  
                                   Key:=strNodKey, _  
                                   Text:=strText  
                                     
                        strNodKey = vbNullString  
                        strParentNodKey = vbNullString  
                    End If  
                Else  
                    j = 0: Exit Do  
                End If  
            Loop  
            If Len(xlWks.Cells(i, 1)) = 0 Then Exit Do  
        Loop  
 
        On Error GoTo 0  
 
    End With  
 
End Sub  
 
   Jak widzimy dane znajdują się w Ark.Arkusz1 od komórki A1. Zmienna i reprezentuje nr. wiersza, j - nr. kolumny.  
 
                strText = xlWks.Cells(i, j)  
                If Len(strText) > 0 Then  
 
do strText trafia zawartość komórki i,j. Jeżeli komórka jest pusta to znaczy że dotarliśmy do końca wiersza układu danych.  
 
                    If j = 1 Then  
                        .Nodes.Add Key:=strText, _  
                                   Text:=strText  
                    Else  
 
Jeżeli j = 1 oznacza to że dodajemy pierwszy poziom drzewa (z kol.A). Zarówno Key (który musi być unikatowy w obrębie całego  
drzewa i po którym będziemy tworzyć relację z kolejnymi poziomami), jak i Text są po prostu zawartością komórki.  
 
                    Else  
                        With xlWks  
                            For iCell = 1 To j  
                                strNodKey = strNodKey & .Cells(i, iCell).Value  
                            Next  
                        End With  
                        strParentNodKey = Left(strNodKey, Len(strNodKey) - Len(strText))  
                         
                        .Nodes.Add relative:=strParentNodKey, _  
                                   relationship:=tvwChild, _  
                                   Key:=strNodKey, _  
                                   Text:=strText  
                                     
                        strNodKey = vbNullString  
                        strParentNodKey = vbNullString  
                    End If  
 
inaczej jest gdy j > 1. Żeby poprawnie utworzyć .Node tak żeby "wyrastał" z odpowiedniej "gałęzi" trzeba ustalić 3 rzeczy:  
  1. strNodeKey - unikalny klucz/nazwa dla .Node, która powstaje ze sklejenia zawartości analizowanego wiersza danych od kol.1  
      do j.  
  2. strParentNodKey - treść klucza jaki przypisaliśmy dla .Node wyższego poziomu (jego "Rodzica"). Zauważmy że ciąg ten będzie  
     zawierał się w strNodeKey. Będzie to ciąg strNodeKey bez ostatniego elementu. Elementem tym jest treść komórki (i,j) :-)  
  3. strText - zawartość danej komórki (i,j)  
 
Znając to założenie treść kodu jest prosta :-) I na dobrą sprawę po zabawie..  
 
Jednak dołóżmy dodatkowe zadanie..  
   Klikamy na dowolny element drzewa i chcielibyśmy wiedzieć:  
       1. na którym poziomie drzewa jesteśmy  
       2. jakie są nazwy (Text) wszystkich .Node ostatniego poziomy   
          dla klikniętego elementu drzewa.  
Jak zwykle lepiej pokazać OCB niż opisywać. Obrazek wyjaśni wszystko.  
 
 
Dim strNodeNames As String, iCount As Integer  
 
 
Private Sub TreeView1_NodeClick(ByVal Node As MSComctlLib.Node)  
    strNodeNames = vbNullString  
    ReadNodesChildrenText Node  
    Me.Label1.Caption = strNodeNames  
      
    iCount = 1  
    HasParent Node  
    Me.Label2.Caption = iCount  
End Sub  
 
Sub ReadNodesChildrenText(ByVal Node As MSComctlLib.Node)  
    Dim lngChildren As Long, i As Long  
    Dim objNode As MSComctlLib.Node  
      
    lngChildren = Node.Children  
    If lngChildren > 0 Then  
        Set objNode = Node.Child.FirstSibling  
 
        For i = 1 To lngChildren  
            If objNode.Children = 0 Then  
                strNodeNames = strNodeNames & objNode.Text & ", "  
            Else  
                ReadNodesChildrenText objNode  
            End If  
            Set objNode = objNode.Next  
        Next  
    End If  
End Sub  
 
Sub HasParent(ByVal Node As MSComctlLib.Node)  
    Dim objNode As MSComctlLib.Node  
      
    On Error Resume Next  
    Set objNode = Node.Parent  
    On Error GoTo 0  
    If Not objNode Is Nothing Then  
        iCount = iCount + 1  
        HasParent objNode  
    End If  
End Sub  
 
Zmienne strNodeNames i iCount zadeklarowałem jako zmienne poziomu modułu UserForm'a.  
Procedura TreeView1_NodeClick raczej nie wymaga tłumaczenia, raczej procedury które wywołuje.  
Procedury ReadNodesChildrenText i HasParent to procedury rekurencyjne. Tzn. Jeżeli zostanie spełniony warunek wywołują same  
siebie. I tak:  
   Procedura ReadNodesChildrenText ma za zadanie określić treść (Text) .Node ostatniego poziomu. I jak działa:  
      do zmiennej lngChildren trafia ilość "dzieci" klikniętego .Node jeżeli = 0 procedura kończy działanie. W przeciwnym razie pętla  
      "po dzieciach" jeżeli dane "dziecko" ma = 0 swoich "Dzieci" zapisujemy jego .Text do zmiennej strNodeNames ponieważ jest  
      .Node ostatniego poziomu którego szukamy. Jeżeli "dane dziecko" ma jednak swoje dzieci procedura wywołuje sama siebie  
      jednak teraz jej argumentem nie jest już kliknięty .Node a jego "dziecko" które posiada swoje "dzieci". I tak do momentu aż  
      lngchildren = 0 i procedura ostatecznie zakończy działanie. Jednak po drodze pozbiera .Text ostatnich elementów drzewa "pod"   
      klikniętym .node  
   Procedura HasParent jest prostsza :-) Jednak o ile poprzednia procedura sprawdzała swoje "dzieci" a więc powiedzmy że była   
      skierowana w rórę drzewa. Tak ta odwrotnie - sprawdza czy dany element posiada rodzica. Jeżeli tak to zwiększa wartość  
      zmiennej iCount o 1 i wywołuje sama siebie jednak jej argumentem nie jest już kliknięty element ale jego "Rodzic". Procedura   
      powtarza się tak długo aż trafi na taki element który nie będzie już miał rodzica. Wtedy zakończy działanie jednak w zmiennej   
      iCount pozostanie info. O ilość poziomów "w dół" od klikniętego elementu.   omawiany przykład.
  treeview_rekur.zip
Na tym zabawę kończę. Pliczek do wglądu ------>>>