Sdean
Sdean

Reputation: 247

Delphi VirtualStringTree and a Queue

Hi i've a project that uses the VirtualStringTree , with this Record :

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

And i've these Procedures :

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;

We Have these 4 Students in Order:

What i want is this :

1 : StudentB raises his Hand :

2 : StudentC raises his Hand :

StudentC will not Jump on StudentB ( Because StudentB is still raising his Hand )

3 : StudentD raises his Hand :

StudentC will not Jump on StudentB or StudentC ( Because both are still raising their Hands )

4 : StudentB withdraws his hand :

StudentB will be moved to the last position

I tried to use this procedure :

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;

Thank you all

Upvotes: 0

Views: 1375

Answers (1)

LightBulb
LightBulb

Reputation: 964

Whenever you want to implement a custom sort order in VirtualStringTree, you should use OnCompareNodes event. Here's the simple example based on your code:

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;

Note that I've written this without testing (from my memory), so you may have to tweak it a bit to suit your needs. For better understanding how this works, check the documentation.

If you include toAutoSort in the Options.AutoOptions set (set it to True in the Object Inspector), this event is automatically called every time a node is inserted or deleted, or the node's Text is changed. However, if sorting depends on other elements of node data (your TStudentsSession record in this case), you will have to manually call SortTree method.

Another simple way of sorting the tree is by using Header.SortColumn, but in that case you're limited to a single column.

Upvotes: 2

Related Questions