Mirror

Sort a TTreeView so that it displays folders first and files second (Views: 100)


Problem/Question/Abstract:

I'm populating a treeview from a folder location. At this moment I know how to scan that folder for files and other folders. How can I perform a search so that the items get grouped first the folders and then the files (like Windows Explorer)?

Answer:

You have basically two options:

Do two separate scans, one for folders only, one for files only. This way the treeview gets populated in two chunks. But the two sections will not be sorted alphabetically or so, since the order in which Findfirst/FindNext retrieves the files/folders is undefined (or better: nobody outside MS knows how it is defined ).

or

Sort the treeview after you have populated it using a single scan. By blocking the treeview from redrawing while you populate it (Items.beginUpdate/items.endupdate) you can do populating and sorting without any visual upheaval.

You do the sorting by calling the handling CustomSort method of the treeview. There are two ways to use it, you can hand it a custom comparison function or you can let it call the treeviews OnCompare event to get a descision fromn you which node of a pair to consider "larger". The second method may be easier for you, so you would construct you treeview population code like

{ ... }
treeview1.items.beginupdate;
try
  PopulateTreeView;
  treeview1.CustomSort(nil, 0);
finally
  treeview1.items.endupdate;
end;
{ ... }

and handle the OnCompare event to compare two nodes. The comparison would inspect two items of data for each node: whether it is a folder node or not, and the nodes Text. So you need some way to indicate that a node stands for a folder. You could use the nodes Data property for that, e.g. store Pointer(1) into it for a folder and Nil (Pointer(0)) for a file. In this case the compare event handler would be this:

procedure TForm1.TreeView1Compare(Sender: TObject; Node1, Node2: TTreeNode;
  Data: Integer; var Compare: Integer);
begin
  if node1.Data = node2.Data then
    compare := AnsiCompareText(Node1.Text, NOde2.Text)
  else if Assigned(node1.data) then
    compare := -1 {folders sort before files}
  else
    compare := 1;
end;

<< Back to main page