Объект TreeView


Постановка задачи проста : надо создать структуру данных типа каталога с вложенными подкаталогами. Ну самое банальное "дерево" с бананами. А ещё лучше прикрутить к этому каталогу группу чего-либо. Ну, например, будем делать справочник зап.частей для Запорожца.

Примечание. В примере будут использоваться объекты из набора VB5 (MS Data Bound Grid Control 5.0, MS Windows Common Controls 5.0). Всё без проблем переносится на VB6 с использованием объектов OLEDB (MS DataGrid Control 6.0 (OLEDB), MS Windows Common Controls 6.0).

На начальном этапе форма будет выглядеть примерно так :

Пример TreeView Form

В объект ImageList1 добавим для начала две иконки, которые будут для наглядности показывать закрытую и открытую папки. При выборе иконок лучше всего поставить в General Properties объекта ImageList1 размер 16x16. Иконки можно взять наподобие таких : || и |/. Соответственно, в такой же последовательности их и добавлять в объект TreeView1. Ну это всё лирическое отступление. В процессе в форму надо будет добавить кнопки и дополнительные поля ввода.
Делаем в Access'е БД zaz.mdb и такие две таблички (tCATALOG и tSPARE) :

tCATALOG :
Field Name
Data Type
  GroupID   Auto Number
  GroupParentKod   Long Integer
  GroupName   Text
tSPARE :
Field Name
Data Type
  SpareID   Auto Number
  SpareGroup   Long Integer
  SpareName   Text
  SpareCount   Single
  и т.д.  

Для пущей верности можно указать Relationship [tCATALOG].GroupID -> [tSPARE].SpareGroup

Теперь самое главное - научить форму правильно строить "дерево" каталогов.

Module1.bas :
Option Explicit
Public gvDatabasePath As String
Public GroupBookMark() As Variant
Sub Main()
    gvDatabasePath = App.Path & "\zaz.mdb"
    ChDir App.Path
    frmCatalog.Show
End Sub
frmCatalog.frm :
Dim i As Long
Dim NodX As Node
Private Sub Form_Load()
    DataCatalog.DatabaseName = gvDatabasePath
    DataSpare.DatabaseName = gvDatabasePath
    DataCatalog.RecordSource = "SELECT * FROM tCATALOG WHERE GroupID>0" _
	"ORDER BY GroupParentKod, GroupName"
    DataCatalog.Refresh
    DataSpare.RecordSource = "SELECT * FROM tSPARE"		
    ' Можно выбрать конечно всё или добавить "WHERE SpareGroup=-1",
    ' чтобы ничего не попало в выборку, 
    ' пока не будет конкретно указана нужная группа.
    DataSpare.Refresh
    ReadGroups	
End Sub

Private Sub ReadGroups()
    ReDim GroupBookMark(0)
    
    tvCatalog.Nodes.Clear
    Set NodX = tvCatalog.Nodes.Add(, , "Root", "All spares", 1, 2)
    If DataCatalog.Recordset.RecordCount < 1 Then Exit Sub
    With DataCatalog.Recordset
       .MoveFirst
       Do While .EOF = False
       Select Case !GroupParentKod
           Case 0
               Set NodX = tvCatalog.Nodes.Add("Root", tvwChild, _
                                              "Nodes" & !GroupID, !GroupName, 1, 2)
           Case Is > 0
               Set NodX = tvCatalog.Nodes.Add("Nodes" & !GroupParentKod, tvwChild, _
                                              "Nodes" & !GroupID, !GroupName, 1, 2)
       End Select
       ReDim Preserve GroupBookMark(UBound(GroupBookMark) + 1)
       GroupBookMark(UBound(GroupBookMark)) = .Bookmark
       .MoveNext
       Loop
    End With
' Устанавливаем иконки для узлов (это можно сделать для того, чтобы
' явно указать, что узел содержит "группу потомков".
' Но для этого в объект ImageList1 надо добавить ещё парочку иконок
' с соответствующими изображениями)
For i = 1 To tvCatalog.Nodes.Count
    If tvCatalog.Nodes.Item(i).Children > 0 Then
        tvCatalog.Nodes.Item(i).Image = 3
        tvCatalog.Nodes.Item(i).ExpandedImage = 4
    End If
Next i
End Sub
Пояснения :
Как видно из вышеизложенного, структура таблицы tCATALOG построена по следующему принципу:
Узлы верхнего уровня имеют значение !GroupParentKod=0
Ветвь дерева, отходящая от такого узла в поле !GroupParentKod содержит значение !GroupID "родителя" и по такому же принципу "ветвится" вглубь. При инициализации объекта DataCatalog данные сортируются как раз по полю GroupParentKod. Таким образом обеспечивается точная последовательность создания узлов (вначале узлы верхнего уровня, затем их "чада").
При заполнении объекта tvCatalog первым делом создаётся узел "Root". Это необходимо для выбора "нулевого" уровня при создании узлов с !GroupParentKod=0. Конечно, при использовании такого механизма построения "дерева", когда нет необходимости редактировать структуру "дерева", можно не создавать "нулевой" узел, а помещать в "корень" узлы с !GroupParentKod=0:
...
Select Case !GroupParentKod
    Case 0
        Set NodX = tvCatalog.Nodes.Add(, , "Nodes" & !GroupID, !GroupName, 1, 2)
    Case Is > 0
        Set NodX = tvCatalog.Nodes.Add("Nodes" & !GroupParentKod, tvwChild, _
                                       "Nodes" & !GroupID, !GroupName, 1, 2)
End Select
...

uncle-b@cybergal.com (Борис Феофанов)
Klaipeda, Lithuania