按字母顺序排序J树节点

8

我已经加载了我的JTree来查看我的目录结构,如我在代码和输出图像中所示。这里,树节点默认按字母顺序排序,但我的另一个要求是,我想根据目录名称的第二个名称对所有节点进行排序,而不必实际重命名目录。我已经用下划线标出需要对其进行排序的名称。请给我提供一些建议。

import java.io.File;
import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

public class FILE_NAME {
public static void main(String[] args) {
       JFrame frame = new JFrame("My Jtree");

       File root = new File("C:/java");
       JTree tree = new JTree(new FileTreeModel(root));
       frame.setSize(300, 300);
       frame.setVisible(true);
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.add(tree);
       frame.setVisible(true);            
      }
    }

class FileTreeModel implements TreeModel {

protected File root;

public FileTreeModel(File root) {
    this.root = root;
}

@Override
public Object getRoot() {
    return root;
}

@Override
public boolean isLeaf(Object node) {
    return ((File) node).isFile();
}

@Override
public int getChildCount(Object parent) {
    String[] children = ((File) parent).list();
    if (children == null) {
        return 0;
    }
    return children.length;
}

@Override
public Object getChild(Object parent, int index) {
    String[] children = ((File) parent).list();
    if ((children == null) || (index == children.length)) {
        return null;
    }
    return new File((File) parent, children[index]);
}

@Override
public int getIndexOfChild(Object parent, Object child) {
    String[] children = ((File) parent).list();
    String childname = ((File) child).getName();
    if (children == null) {
        return -1;
    }
    for (int i = 0; i == children.length; i++) {
        if (childname.equals(children[i])) {
            return i;
        }
    }
    return -1;
}

@Override
public void valueForPathChanged(TreePath path, Object newvalue) {
}

@Override
public void addTreeModelListener(TreeModelListener l) {
}

@Override
public void removeTreeModelListener(TreeModelListener l) {
}
}

输出

输入图像描述


请给我一些建议: 1)描述您已经尝试过的内容。 2)提出一个问题。 - Andrew Thompson
我还在努力尝试,很快会告诉你。 - Jony
1
如果您不需要动态排序,最简单的方法是在构建TreeModel时对其进行排序。 - Robin
3个回答

10
最灵活的解决方案是构建一个简单的DefaultMutableTreeNode扩展,每次添加新元素时对节点的子元素进行排序(感谢这篇文章提供的一般思路):
public class SimpleTreeNode
extends DefaultMutableTreeNode
{
    private final Comparator comparator;

    public SimpleTreeNode(Object userObject, Comparator comparator)
    {
        super(userObject);
        this.comparator = comparator;
    }

    public SimpleTreeNode(Object userObject)
    {
        this(userObject,null);
    }

    @Override
    public void add(MutableTreeNode newChild)
    {
        super.add(newChild);
        if (this.comparator != null)
        {
            Collections.sort(this.children,this.comparator);
        }
    }
}

这个解决方案非常灵活,因为它允许您为每个层级的树甚至每个文件夹设置不同的排序方法。(当然,您也可以非常容易地在所有地方使用相同的或没有Comparator。)

如果有帮助的话,下面是我使用SimpleTreeNode时用过的两种排序方法:

public class Comparators
{
    /** Allows alphabetical or reverse-alphabetical sorting
     * 
     */

    public static class AlphabeticalComparator
    implements Comparator
    {
        private final boolean order;

        public AlphabeticalComparator()
        {
            this(true);
        }

        public AlphabeticalComparator(boolean order)
        {
            this.order = order;
        }

        @Override
        public int compare(Object o1, Object o2)
        {
            if (order)
            {
                return o1.toString().compareTo(o2.toString());
            }
            else
            {
                return o2.toString().compareTo(o1.toString());
            }
        }
    }

    /** Allows sorting according to a pre-defined array
     * 
     */

    public static class OrderComparator
    implements Comparator
    {
        private final String[] strings;

        public OrderComparator(String[] strings)
        {
            this.strings = strings;
        }

        @Override
        public int compare(Object o1, Object o2)
        {
            String s1 = o1.toString();
            String s2 = o2.toString();
            int i1 = -1;
            int i2 = -1;
            for (int j = 0; j < strings.length; j++)
            {
                if (s1.equals(strings[j]))
                {
                    i1 = j;
                }
                if (s2.equals(strings[j]))
                {
                    i2 = j;
                }
            }
            if (i1 == -1 || i2 == -1)
            {
                throw new Error("Can't use this comparator to compare "+o1+" and "+o2);
            }
            else
            {
                return Integer.compare(i1,i2);
            }
        }
    }
}

3
就像这样:
public void sortTree() {
    treeModel.reload(sort(rootNode));
}

public DefaultMutableTreeNode sort(DefaultMutableTreeNode node) {

    //sort alphabetically
    for(int i = 0; i < node.getChildCount() - 1; i++) {
        DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(i);
        String nt = child.getUserObject().toString();

        for(int j = i + 1; j <= node.getChildCount() - 1; j++) {
            DefaultMutableTreeNode prevNode = (DefaultMutableTreeNode) node.getChildAt(j);
            String np = prevNode.getUserObject().toString();

            System.out.println(nt + " " + np);
            if(nt.compareToIgnoreCase(np) > 0) {
                node.insert(child, j);
                node.insert(prevNode, i);
            }
        }
        if(child.getChildCount() > 0) {
            sort(child);
        }
    }

    //put folders first - normal on Windows and some flavors of Linux but not on Mac OS X.
    for(int i = 0; i < node.getChildCount() - 1; i++) {
        DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(i);
        for(int j = i + 1; j <= node.getChildCount() - 1; j++) {
            DefaultMutableTreeNode prevNode = (DefaultMutableTreeNode) node.getChildAt(j);

            if(!prevNode.isLeaf() && child.isLeaf()) {
                node.insert(child, j);
                node.insert(prevNode, i);
            }
        }
    }

    return node;

}

1
这段代码无法正确工作。在内部循环中交换节点会导致后续的比较使用错误的节点。最好搜索最小值,并在必要时在末尾进行交换。 - dmolony
同时,两个循环都结束得太早了。代码只会进入具有两个或更多子文件夹的文件夹,并且最后一个子文件夹永远不会被比较。 - dmolony

2
您可以使用 Arrays.sort() 方法,该方法使用 Comparator,并编写自己的比较器,按照自己的规则比较条目,例如:
String[] children = ((File) parent).list();
Arrays.sort(children, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        // do your comparison
    }
});

在模型方法中,它将被重载,因此您可以考虑将目录列表保存在某个模型私有字段中,并检查模型方法调用时目录是否未更改(比较File.lastModified()将有所帮助)。如果是 - 保存新的列表。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接