VirtualTreeView中的节点排序 - OnCompareNodes不会触发所有要比较的节点

时间:2016-11-28 14:19:32

标签: sorting delphi virtualtreeview

我对VirtualTreView(v 6.1.0 / Delphi 10 Seattle)有一个(奇怪的)排序问题。我已经研究了更新版本的VTV,并没有提到类似的行为。

我会发布完整的源代码,但让我先解释一下我要完成的事情:

vtv sorting nodes issue

  1. 我想要排序的节点
  2. 每个节点都有一种阶段 - 节点阶段确定节点的排序顺序(在该阶段)
  3. 我希望在按阶段排序值选择特定阶段时对节点进行排序。那些未包含在舞台中的节点将被设置为不可见。
  4. 这是我正在使用的记录:

    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,则另一个节点将不再与所选阶段中存在的其余节点进行比较。如何强制其他节点仍与其他同级节点匹配?

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;

坦率地说,这不是我对比较节点的工作方式所期望的。