Sort Jtree Node Alphabetically
Asked Answered
E

3

8

I have loaded my JTree to view My directory structure as shown in my code and output image. Here, Tree nodes are by default sorted in alphabetical order, but my other requirement is that I want to sort all nodes according to second name of directory name without actually renaming the directory. I have underlined the name on which I need to sort the JTree node. Please suggest me something.

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) {
}
}

OUTPUT

enter image description here

Etui answered 15/3, 2012 at 5:11 Comment(3)
"please suggest me something" 1) Describe what you have tried. 2) Ask a question.Commingle
well i am still trying will let you know soonEtui
In case you do not need dynamic sorting, the easiest way is to sort your TreeModel when you construct itHumdinger
I
2

you can use Arrays.sort() method that uses Comparator, and write your own comparator which compares entries by your own rules, like that:

String[] children = ((File) parent).list();
Arrays.sort(children, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        // do your comparison
    }
});

In the model methods it will be overload, so you may consider to save directory listing in some model private field and check if directory was not changed in model methods invocation (comparing File.lastModified() will help). If it was - save new listing.

Ingratitude answered 15/3, 2012 at 12:11 Comment(0)
H
10

The most flexible solution is to build a simple extension of DefaultMutableTreeNode that sorts the node's children every time a new element is added (credit to this article for the general idea):

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);
        }
    }
}

This solution is very flexible because it allows you to have different sorting methods for each level of the tree or even for each folder. (Of course you can also very easily use the same or no Comparator everywhere.)

In case this helps anyone, see below two sorting methods that I have used with 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);
            }
        }
    }
}
Haricot answered 11/11, 2018 at 2:47 Comment(0)
B
3

It goes like this :

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;

}
Breastpin answered 29/3, 2013 at 13:30 Comment(2)
This code does not work correctly. Swapping nodes inside the inner loop causes subsequent comparisons to use the wrong nodes. Better to search for the lowest value and swap at the end if required.Botvinnik
Also both loops end too early. The code only descends into folders with two or more children, and the last child is never compared.Botvinnik
I
2

you can use Arrays.sort() method that uses Comparator, and write your own comparator which compares entries by your own rules, like that:

String[] children = ((File) parent).list();
Arrays.sort(children, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        // do your comparison
    }
});

In the model methods it will be overload, so you may consider to save directory listing in some model private field and check if directory was not changed in model methods invocation (comparing File.lastModified() will help). If it was - save new listing.

Ingratitude answered 15/3, 2012 at 12:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.