У меня есть (странная) проблема сортировки с VirtualTreView (v 6.1.0/Delphi 10 Seattle). Я просмотрел более поздние версии VTV и не упоминается подобное поведение.Сортировка узлов в VirtualTreeView - OnCompareNodes не срабатывает для всех узлов, которые будут сравниваться
я выложу полный исходный код, но позвольте мне объяснить, что я пытаюсь выполнить:
- Есть узлы, которые я хотел, чтобы отсортировать
- Каждый узел имеет стадию - где этап узла определяет порядок сортировки узла (на этом этапе)
- Я хотел бы, чтобы узлы сортировались, когда конкретный этап выбирался по их значению сортировки сцены. Те узлы, которые не включены в сцену, должны быть установлены невидимыми.
Вот запись, я использую:
PRecord = ^TRecord;
TRecord = record
SortOrder : array [0..4] of integer;
PositionAdded : integer;
end;
Вот как добавлены узлы:
procedure TVTVSortForm.FormCreate(Sender: TObject);
var
vn : PVirtualNode;
pr : PRecord;
begin
tree.NodeDataSize := SizeOf(TRecord);
vn := tree.AddChild(nil);
pr := PRecord(tree.GetNodeData(vn));
pr.PositionAdded := vn.Index;
pr.SortOrder[0] := 0; //first in 0 - removed in later
pr.SortOrder[1] := -1;
pr.SortOrder[2] := -1;
pr.SortOrder[3] := -1;
pr.SortOrder[4] := 2; //third in 4
vn := tree.AddChild(nil);
pr := PRecord(tree.GetNodeData(vn));
pr.PositionAdded := vn.Index;
pr.SortOrder[0] := 1; //second in 0
pr.SortOrder[1] := 0; //first in 1
pr.SortOrder[2] := 1; //second in 2
pr.SortOrder[3] := 1; //second in 3
pr.SortOrder[4] := 0; //first in 4
vn := tree.AddChild(nil);
pr := PRecord(tree.GetNodeData(vn));
pr.PositionAdded := vn.Index;
pr.SortOrder[0] := 2; // third in 0
pr.SortOrder[1] := 2; //third in 1
pr.SortOrder[2] := 0; //first in 2
pr.SortOrder[3] := -1; //removed in 3
pr.SortOrder[4] := 1; //second in 4
vn := tree.AddChild(nil);
pr := PRecord(tree.GetNodeData(vn));
pr.PositionAdded := vn.Index;
pr.SortOrder[0] := -1; //not in 0
pr.SortOrder[1] := 1; //second in 1
pr.SortOrder[2] := 2; //third in 2
pr.SortOrder[3] := 0; // first in 3
pr.SortOrder[4] := -1; // not in 4
tree.ValidateNode(nil, true);
end;
"Этапы" являются SortOrder индексы. SortOrder [x]: = y означает, что порядок узла на этапе X должен быть y. Например, SortOrder [2] = 0 означает, что на этапе 2 узел должен быть первым узлом. SortOrder [3] = -1 означает, что узел «не существует» на этапе 3.
Существует радиогруппа, имеющая 5 элементов (0 ... 4), представляющих сцену. При выборе стадии узлы должны быть отсортированы в соответствии с их значение SortOrder на стадии выбранного (я также скрываются узлы, которые не существуют в стадии:
procedure TVTVSortForm.rgFilterAndSortClick(Sender: TObject);
begin
tree.Sort(tree.RootNode, 0, sdAscending);
tree.IterateSubtree(
nil,
procedure (Sender: TBaseVirtualTree; Node: PVirtualNode; Data: Pointer; var Abort: Boolean)
var
d : PRecord;
begin
d := PRecord(tree.GetNodeData(Node));
//tree.IsVisible[Node] := -1 <> d.SortOrder[rgFilterAndSort.ItemIndex];
end,
nil);
end;
OnCompare выглядит следующим образом:
procedure TVTVSortForm.treeCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
var
d1, d2 : PRecord;
begin
d1 := PRecord(Sender.GetNodeData(Node1));
d2 := PRecord(Sender.GetNodeData(Node2));
if (-1 <> d1.SortOrder[rgFilterAndSort.ItemIndex]) AND (-1 <> d2.SortOrder[rgFilterAndSort.ItemIndex]) then
result := d1.SortOrder[rgFilterAndSort.ItemIndex] - d2.SortOrder[rgFilterAndSort.ItemIndex];
end;
Поэтому я только сравнивающие те узлы, которые существуют в выбранном этапе (т.е. SortOrder [стадии] <> -1).
GetText показывает порядок сортировки для выбранного этапа + исходное положение узла в время добавления в дерево.
Теперь, что происходит, когда вы запускаете программу и перейти (выберите радиокнопку/щелчок) на стадии (3), порядок 1,0 вместо 0,1 (я опускаю «-1 "узлы).
Если после выбора этапа (3) вы выбираете (1), то (3) -> этап 3 сортируется в порядке. Но затем перейдите на этап (0), (2), (4), а порядок равен 1,2,0 вместо 0,1,2.
Любые идеи, почему это не работает (как и ожидалось)?
Я заметил, что когда два узла входят в OnCompare: если один из узлов имеет -1 для выбранного этапа, другой узел больше не будет сравниваться с остальными узлами, которые существуют на выбранном этапе. Как заставить другой узел по-прежнему согласовываться с другими узлами той же стадии?
Когда 'SortOrder' равно -1 для одного узла, а не для другого, то' Result' не определено. Сравнение должно определять * полное упорядочение *; если вы не определяете сравнение между * all * возможными парами, то базовый алгоритм сортировки даст неожиданные результаты, такие как остановка до того, как все узлы будут отсортированы. –
@Rob, извините, но результат всегда задан 0 (Node1
Torpedo
Это дает ту же проблему. Результат нуля означает, что узлы равны. Предположим, что у вас есть узлы, а для узла 1 установлено значение -1. Узел 2 сравнится с ним равным, и так будет узел 3, потому что вы пропустили сравнение. По транзитивности это должно означать, что узел 2 равен узлу 3, но если ваша функция сравнения возвращает другой ответ, то у вас нет общего порядка, и алгоритм сортировки может выйти из строя. –