0

嗨,我有一个使用 VirtualStringTree 的项目,带有此记录:

type
  TStudentsSession = record
    StudentName : String;
    StudentClass : String;
    StudentHandRaised:Boolean;
  end;

我有这些程序:

Procedure TMainForm.StudentHandRaised(AStudentName: String)
var
  Node: PVirtualNode;
  Data: ^TStudentsSession;
begin
  Node := StudentsVst.GetFirst;
  while Node <> nil do
  begin
    Data := StudentsVst.GetNodeData(Node);
    if Data.StudentName = AStudentName then
    begin
      Data.StudentHandRaised := True;
      Break;
    end;
    Node := StudentsVst.GetNext(Node);
  end;
end;

Procedure TMainForm.StudentHandsDown(AStudentName: String)
var
  Node: PVirtualNode;
  Data: ^TStudentsSession;
begin
  Node := StudentsVst.GetFirst;
  while Node <> nil do
  begin
    Data := StudentsVst.GetNodeData(Node);
    if Data.StudentName = AStudentName then
    begin
      Data.StudentHandRaised := False;
      Break;
    end;
    Node := StudentsVst.GetNext(Node);
  end;
end;

我们按顺序排列了这 4 名学生:

  • 学生A
  • 学生B
  • 学生C
  • 学生D

我想要的是这个:

1:StudentB举手:

  • 学生B
  • 学生A
  • 学生C
  • 学生D

2:StudentC举手:

  • 学生B
  • 学生C
  • 学生A
  • 学生D

StudentC 不会跳到 StudentB 上(因为 StudentB 还在举手)

3:StudentD举手:

  • 学生B
  • 学生C
  • 学生D
  • 学生A

StudentC 不会跳到 StudentB 或 StudentC 上(因为两者都还在举手)

4:StudentB收回手:

  • 学生C
  • 学生D
  • 学生A
  • 学生B

StudentB 将被移动到最后一个位置

我尝试使用此程序:

procedure TMainForm.ReArrangeStudents;
var
  Node, PreviNode: PVirtualNode;
  Data: ^TStudentsSession;
begin
  Node := StudentsVst.GetFirst;
  while Node <> nil do
  begin
    Data := StudentsVst.GetNodeData(Node);
    if Data.StudentHandRaised then
      PreviNode := StudentsVst.GetPrevious(Node, False)
    else
      PreviNode := StudentsVst.GetNext(Node);
    StudentsVst.MoveTo(Node, PreviNode, amInsertBefore, False);
    Node := StudentsVst.GetNext(Node);
  end;
end;

谢谢你们

4

1 回答 1

2

每当您想在 中实现自定义排序顺序时VirtualStringTree,都应该使用OnCompareNodesevent. 这是基于您的代码的简单示例:

procedure TMainForm.StudentsVstCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
var
  Data1, Data2: ^TStudentsSession;
begin
  Data1 := Sender.GetNodeData(Node1);
  Data2 := Sender.GetNodeData(Node2);
  // If both students have their hands raised, compare by student name
  if Data1.StudentHandRaised and Data2.StudentHandRaised then
  begin
    Result := CompareStr(Data1.StudentName, Data2.StudentName);
  end
  else
  begin
    // If only one student has his/her hand raised, move him/her before the other one
    if Data1.StudentHandRaised and (not Data2.StudentHandRaised) then
      Result := 1
    else if (not Data1.StudentHandRaised) and Data2.StudentHandRaised then
      Result := -1
    // If both students have their hands down, compare by student name
    else
      Result := CompareStr(Data1.StudentName, Data2.StudentName);
  end;
end;

请注意,我在没有测试的情况下编写了此代码(根据我的记忆),因此您可能需要对其进行一些调整以满足您的需要。为了更好地理解这是如何工作的,请查看文档。

如果包含toAutoSortOptions.AutoOptions集合中(True在 Object Inspector 中将其设置为),则每次插入或删除节点或更改节点的 Text 时都会自动调用此事件。但是,如果排序依赖于节点数据的其他元素(在这种情况下是您的 TStudentsSession 记录),您将不得不手动调用SortTree方法。

另一种对树进行排序的简单方法是使用Header.SortColumn,但在这种情况下,您仅限于单列。

于 2013-09-02T05:27:12.030 回答