ПОНЯТНО О Visual Basic NET (том 3)

Заполняем TreeView в коде


Предоставим пользователю нашего приложения возможность, запустив проект, самому заполнять произвольное дерево, причем так, как это делается в Редакторе вершин дерева. Для этого достаточно запрограммировать работу 4 кнопок, которые вы видите на Рис. 20.16. Все кнопки действуют по отношению к любой выделенной вершине и смысл их ясен без объяснений. Текстовое поле служит для ввода названия вершины.

Но предварительно мы должны кое-что о дереве узнать. Сначала о терминологии.

Вершина – человек. От человека тянутся вниз и направо ветки к его сыновьям (так называемые дочерние вершины – Child). По отношению к сыновьям родитель является родительской вершиной (Parent). Адам – корень. Нажимая в режиме проектирования кнопку Add Root, мы можем добавить к дереву сколько угодно корней. Братья по отношению друг к другу называются Sibling.

Свойства и методы дерева и вершин. Каждая вершина является объектом класса TreeNode. Каждая вершина обладает свойством – коллекцией Nodes – это дочерние вершины (только дочерние, без внуков, правнуков и более отдаленных потомков). Сколько вершин на дереве – столько и коллекций. Но некоторые коллекции – пустые (у кого-то нет детей). Каждый элемент коллекции – это тоже объект класса TreeNode, то есть вершина. Вот такая, довольно сложная, но стройная картина получается.

У каждой вершины есть метод Remove – он уничтожает вершину со всеми ее потомками. Есть свойство Parent – это родительская вершина. Каждую вершину можно выделить своим цветом фона (свойство BackColor) и цветом шрифта (свойство ForeColor). Метод Expand осуществляет нажатие на плюсик у вершины, то есть показывает ее дочерние вершины. Метод ExpandAll показывает не только дочерние вершины, но всех потомков.

Также у вершины есть метод GetNodeCount, который сообщает нам количество вершин-потомков данной вершины. У метода есть булевский параметр: True указывает, что считать нужно всех потомков, False – только дочерние вершины.

Методы Expand и ExpandAll, а также GetNodeCount есть и у дерева TreeView. Здесь True указывает, что считать нужно все вершины дерева, False – только корни.


У дерева TreeView есть также свойство SelectedNode. Оно имеет своим значением выделенную вершину.

Простой вариант программы. Создайте проект с TreeView, 4 кнопками и текстовым полем. TreeView не заполняйте, он должен до запуска проекта быть пустым. Введите в окно кода следующие 5 процедур. Сразу же оговорюсь, что текст процедур данного варианта максимально упрощен. Я жертвовал целесообразностью и надежностью ради понятности:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        TV.Nodes.Add("Адам")

End Sub



Private Sub Создай_сына_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Создай_сына.Click

        Dim Вершина As New TreeNode(TextBox1.Text)

        TV.SelectedNode.Nodes.Add(Вершина)

End Sub

Private Sub Создай_брата_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Создай_брата.Click

        Dim Вершина As New TreeNode(TextBox1.Text)

        TV.SelectedNode.Parent.Nodes.Add(Вершина)

End Sub

Private Sub Переименуй_Click(ByVal sender As Object, ByVal e As EventArgs)  Handles Переименуй.Click

        TV.SelectedNode.Text = TextBox1.Text

End Sub

Private Sub Удали_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Удали.Click

        TV.SelectedNode.Remove()

End Sub

Пояснения: У коллекции Nodes, как и у всякой коллекции, есть метод Add, который добавляет в коллекцию элемент – объект класса TreeNode. В качестве параметра метода мы можем указать свойство Text

этого объекта (в процедуре Form1_Load мы указали "Адам") или заранее созданный объект класса TreeNode (так мы делаем в других процедурах проекта).

Первой выполняется процедура Form1_Load. В пустом дереве она создает вершину Адам. Смысла в этом нет, но мне так проще объяснять.

Не надо сразу же нажимать на кнопку Удали. Поскольку кроме Адама других вершин на дереве нет, именно она и будет выбранной (выделенной темным цветом), а значит будет удалена процедурой Удали_Click. Дерево опустеет и дальше нам не с чем будет работать.



Переименуйте эту вершину, набрав текст в текстовом поле и нажав кнопку Переименуй. Поскольку кроме Адама других вершин на дереве нет, именно она и будет выбранной, а значит будет переименована процедурой Переименуй_Click.

Щелкните по кнопке Создай сына. Первым выполнится оператор

        Dim Вершина As New TreeNode(TextBox1.Text)

Он создает объект Вершина класса TreeNode. Свойство Text

этого объекта определяется значением параметра. У нас это текст в текстовом поле.

Вторым выполнится оператор

        TV.SelectedNode.Nodes.Add(Вершина)

Поскольку выделен Адам, то к коллекции Nodes его сыновей (пустой пока), добавляется только что созданная вершина, что вы и увидите сразу же на экране, щелкнув по появившемуся плюсику. Щелкните по кнопке Создай сына несколько раз. На экране вы увидите несколько сыновей Адама.

Выделите одного из сыновей и щелкните по кнопке Создай сына. Теперь выделен сын и поэтому вершина будет добавлена к коллекции Nodes сына, а не Адама. На экране появится внук.

Выделяя того или иного из сыновей или внуков, щелкайте по кнопке Создай сына, предварительно вводя разный текст в текстовое поле. Вы увидите, как на дереве появляются внуки, правнуки и более отдаленные потомки.

Кнопка Создай брата вроде бы ни к чему, и без нее все работает. Но она мне пригодилась для объяснения свойства Parent. Выделите одну из вершин (но не корень) и нажмите кнопку. В операторе

        TV.SelectedNode.Parent.Nodes.Add(Вершина)

мы видим вот что:

TV.SelectedNode

Выбранная вершина

TV.SelectedNode.Parent

Родитель выбранной вершины

TV.SelectedNode.Parent.Nodes

Коллекция сыновей родителя выбранной вершины, то есть братья выбранной вершины

Надежный вариант программы. Наша программа делает далеко не все, что нужно, и совсем не предохранена от «неправильных» щелчков по кнопкам. Так, нам не удастся создать брата Адаму. Удалив Адама, мы окажемся не у дел. И так далее. Пишем надежный вариант программы:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load



        Dim Вершина As TreeNode

        For Each Вершина In TV.Nodes

            Вершина.Remove()

        Next

End Sub

Private Sub Создай_сына_Click( ByVal sender As Object, ByVal e As EventArgs)  Handles Создай_сына.Click

        Dim Вершина As New TreeNode(TextBox1.Text)

        If TV.GetNodeCount(True) = 0 Then

            TV.Nodes.Add(Вершина)

            TV.Focus()

        ElseIf TV.SelectedNode Is Nothing Then

            MsgBox("Выберите вершину")

        Else

            TV.SelectedNode.Nodes.Add(Вершина)

            Вершина.Parent.Expand()

        End If

End Sub

Private Sub Создай_брата_Click(ByVal sender As Object, ByVal e As EventArgs)  Handles Создай_брата.Click

        Dim Вершина As New TreeNode(TextBox1.Text)

        If TV.GetNodeCount(True) = 0 Then

            TV.Nodes.Add(Вершина)

            TV.Focus()

        ElseIf TV.SelectedNode Is Nothing Then

            MsgBox("Выберите вершину")

        ElseIf TV.SelectedNode.Parent Is Nothing Then

            TV.Nodes.Add(Вершина)

        Else

            TV.SelectedNode.Parent.Nodes.Add(Вершина)

        End If

End Sub

Private Sub Переименуй_Click(ByVal sender As Object, ByVal e As EventArgs)  Handles Переименуй.Click

        If TV.GetNodeCount(True) = 0 Then

            MsgBox("Дерево пусто")

        ElseIf TV.SelectedNode Is Nothing Then

            MsgBox("Выберите вершину")

        Else

            TV.SelectedNode.Text = TextBox1.Text

        End If

End Sub

Private Sub Удали_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Удали.Click

        If TV.GetNodeCount(True) = 0 Or TV.SelectedNode Is Nothing Then Exit Sub

        TV.SelectedNode.Remove()

End Sub

Пояснения: Процедуре Form1_Load я придумал другое дело – теперь она очищает дерево, если вы его нечаянно заполнили в режиме проектирования. Поскольку метод Remove уничтожает вершину со всеми ее потомками, достаточно уничтожить все корни дерева, то есть элементы коллекции TV.Nodes, что и делается.



Теперь разберем процедуру для кнопки Переименуй. Ее работа – ключ к пониманию работы других процедур. Переименовывать имеет смысл только тогда, когда дерево не пусто и когда на дереве имеется выделенная вершина. Оператор If в этой процедуре создан для обработки именно такой ситуации, и его можно перевести так:

      Если общее количество вершин дерева = 0, то

             Сообщай, что дерево пусто

      Иначе если не существует выбранной вершины, то

             Сообщай, что надо бы выбрать вершину

      Иначе

             Переименовывай вершину.

Если объект не существует, то в VB говорят, что он «есть ничто»,  по-английски –

Is  Nothing

Поэтому выражение

TV.SelectedNode Is Nothing

можно перевести, как «выбранная вершина есть ничто» или «выбранная вершина не существует».

Логика остальных кнопок ясна из их кода. Кнопки Создай сына и Создай брата при пустом дереве добавляют корень, как я и хотел. Строка

            TV.Focus()

возвращает фокус на дерево, что удобно, но не обязательно.

В процедуре для кнопки Создай брата строка

        ElseIf TV.SelectedNode.Parent Is Nothing Then

обрабатывает следующую ситуацию: Если у выбранной вершины не существует родителя, значит это корень, значит брат ему – тоже корень, значит создавать этого брата придется строкой

            TV.Nodes.Add(Вершина)

В процедуре для кнопки Создай сына строка

            Вершина.Parent.Expand()

избавляет от необходимости жать плюсик на родителе, чтобы увидеть только что созданного сына.

Прочее. Теперь было бы неплохо, чтобы работа пользователя по созданию дерева не пропала даром, а для этого нужно дать ему возможность сохранить созданное дерево, а потом загрузить. Но это нетривиальная задача. Отложите ее на будущее. Я ее разбирать не буду, но идею ее решения вы можете почерпнуть в следующем подразделе.


Содержание раздела