#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