Получить узлы просмотра дерева в отсортированном порядке

#vb6 #treeview

#vb6 #просмотр дерева

Вопрос:

У нас есть устаревшее приложение, написанное на VB6, использующее элемент управления Microsoft по умолчанию TreeView для отображения иерархических данных. Поскольку в этом много информации TreeView , мы подумали о реализации небольшой возможности фильтрации / поиска для пользователей.

Первой попыткой было переключить видимость и сделать видимыми только те узлы (и их родителей), которые соответствуют заданному поиску. Но это было невозможно, поскольку элемент управления Microsoft по умолчанию TreeView не позволяет их узлам быть видимыми или невидимыми.

Итак, вторая попытка — обойти все узлы в дереве и обеспечить видимость узла, когда он соответствует заданному поиску (и прекратить обход). Когда найденный узел не тот, который ищет пользователь, он может «продолжить» поиск и искать следующий узел, который соответствует его критериям.

Пока это работает довольно хорошо, за исключением одной небольшой проблемы. Поиск не работает сверху вниз, поскольку дерево заполняется данными в произвольном порядке сортировки, а затем сортируется путем установки Sorted свойства каждого узла (устаревший код). Таким образом, поиск выполняется по случайно добавленным узлам, и найденные узлы «перепрыгивают» между узлами верхнего уровня ( Nodes коллекция TreeView содержит все узлы в том порядке, в котором они были добавлены, а не только узлы верхнего уровня и не в том порядке, в котором они представлены пользователю).

Есть ли какой-либо способ получить все узлы дерева в том порядке, в котором они показаны пользователю? Мне не нравится изменять устаревший код, который заполняет дерево данными, и сортировка данных перед их добавлением в TreeView может повлиять на производительность.

Пожалуйста, имейте в виду, что я говорю о приложении, написанном на VB6, поэтому не существует такого понятия, как LINQ, для обхода узлов в желаемом порядке.

Вот мой код поиска на данный момент:

 Private Sub cmdSearch_Click()
    Dim oMatch As Node

    Set oMatch = GetNextMatch

    If Not (oMatch Is Nothing) Then
        oMatch.EnsureVisible
        oMatch.Selected = True
        Me.TreeView1.SelectedItem = oMatch
        Me.TreeView1.SetFocus
    End If

End Sub

Private Function GetNextMatch() As Node
    Dim lIndex As Long
    Dim oResult As Node

    For lIndex = mlLastFoundIndex   1 To Me.TreeView1.Nodes.Count
        If IsMatch(Me.TreeView1.Nodes(lIndex).Text) Then
            Set oResult = Me.TreeView1.Nodes(lIndex)
            mlLastFoundIndex = lIndex
            Exit For
        End If
    Next lIndex

    Set GetNextMatch = oResult
End Function

Private Sub txtSearch_Change()
    mlLastFoundIndex = 0
End Sub
  

Комментарии:

1. Похоже, вы уже выяснили основную причину, по которой это сложно, — что сам treeview используется в качестве «основной» структуры данных для этих операций. Если бы вместо этого у вас была отдельная структура данных, вы могли бы реализовать все, что хотите, а затем просто скопировать результаты в treeview. Я могу видеть, где это может потребовать много работы для существующего приложения, но иногда такой рефакторинг оказывается проще в долгосрочной перспективе… меньше отклонений от особого случая к специальному случаю (все из которых трудно предвидеть)

2. Я согласен с DaveInCaz, но не могли бы вы опубликовать код «поиска», с которым вы работаете? Я работал с элементом управления раньше, и это может быть необычно. Узлы, которые, как я полагаю, индексируются, начиная с 0.

3. Нет, индексация с помощью Nodes начинается с 1. Я ввел код поиска в вопрос. Я ищу что-то, что доставляет Me.TreeView1.Nodes в порядке, в котором узлы представлены пользователю.

Ответ №1:

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

 Private Sub Command3_Click()
  If Not TreeView1.SelectedItem Is Nothing Then
    PrintNodesInSortedOrder TreeView1.SelectedItem
  End If
End Sub

Private Sub PrintNodesInSortedOrder(ParentNode As MSComctlLib.Node)
  Dim Nod As MSComctlLib.Node

  Set Nod = ParentNode.Child
  Do While Not Nod Is Nothing
    Debug.Print Nod.Text
    Set Nod = Nod.Next
  Loop

End Sub