我对VirtualTreView(v 6.1.0 / Delphi 10 Seattle)有一个(奇怪的)排序问题。我已经研究了更新版本的VTV,并没有提到类似的行为。
我会发布完整的源代码,但让我先解释一下我要完成的事情:
这是我正在使用的记录:
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 [stage]&lt;&gt; -1)。
GetText显示所选阶段的排序顺序+添加到树时节点的原始位置。
procedure TVTVSortForm.treeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
Data: PRecord;
begin
Data := Sender.GetNodeData(Node);
CellText := Format('s:%d, p:%d', [Data.SortOrder[rgFilterAndSort.ItemIndex], Data.PositionAdded]);
end;
现在,当你启动程序然后(选择单选按钮/单击)到阶段(3)时会发生什么,顺序是1,0而不是0,1(我省略了“-1”节点)。
如果在选择阶段(3)之后选择(1)然后选择(3) - >第3阶段排序好。但是然后转到阶段(0),(2),(4),顺序是1,2,0而不是0,1,2。
任何想法为什么这不起作用(如预期的那样)?
我注意到当两个节点进入OnCompare时:如果其中一个节点的所选阶段为-1,则另一个节点将不再与所选阶段中存在的其余节点进行比较。如何强制其他节点仍与其他同级节点匹配?
答案 0 :(得分:1)
Omg,我一直试图弄清楚过去几天在这里出了什么问题,当然,一旦我在这里发布了我的问题,我就已经弄明白了。
OnCompare需要比较&#34;所有&#34;节点 - 所以跳过一些节点(节点是#34;不在舞台上#34;)是我的代码出错了。
当需要将阶段节点与匹配的不同阶段节点进行比较时,我需要确保阶段节点与其他同阶段节点进行比较。
最后,我重写了这样的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]) then result := -1
else if (-1 = d2.SortOrder[rgFilterAndSort.ItemIndex]) then result := 1
else
if (-1 <> d1.SortOrder[rgFilterAndSort.ItemIndex]) AND (-1 <> d2.SortOrder[rgFilterAndSort.ItemIndex]) then
result := d1.SortOrder[rgFilterAndSort.ItemIndex] - d2.SortOrder[rgFilterAndSort.ItemIndex]
else
begin
//just testing if this ever happens
if (-1 = d1.SortOrder[rgFilterAndSort.ItemIndex]) then Inc(d1.PositionAdded);
if (-1 = d2.SortOrder[rgFilterAndSort.ItemIndex]) then Inc(d2.PositionAdded);
end;
end;
坦率地说,这不是我对比较节点的工作方式所期望的。