Search code examples
javaswingjtreetreenode

JTree - how can i stop children from showing relative path?


Before we start, I'd like to note that I'm rather new to JTree and its relatives.

The children in my nodes show the relative path back to its parent, but I'd like for it not to.

Here is a picture of what it looks like

http://puu.sh/azCJa/8dd84029b7.png JTree

I'd like for it to be like:

testing 0
>testing 1
>>file 1

not

testing 0
>testing 0\testing 1
>>...

Here is some runnable code.

import java.awt.Color;
import java.io.File;
import java.util.Collections;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.border.LineBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeSelectionModel;

public class NGui {

    JFrame frame;
    private JTree tree;

    public NGui() {
        initialize();
    }

    private void initialize() {
        frame = new JFrame();
        frame.setResizable(false);
        frame.setBounds(100, 100, 493, 608);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);

        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setBounds(10, 11, 212, 500);
        frame.getContentPane().add(scrollPane);

        tree = new JTree(addNodes(null, new File(getWorkPath())));
        tree.setRootVisible(false);
        tree.setShowsRootHandles(true);

        tree.setBorder(new LineBorder(new Color(0, 0, 0)));
        tree.getSelectionModel().setSelectionMode(
                TreeSelectionModel.SINGLE_TREE_SELECTION);
        scrollPane.setViewportView(tree);

        tree.getSelectionModel().addTreeSelectionListener(
                new TreeSelectionListener() {
                    @Override
                    public void valueChanged(TreeSelectionEvent e) {
                        treeValueChanged(e);
                    }
                });
    }

    private String getWorkPath() {
        return System.getProperty("user.home") + "\\Program Name\\";
    }

    private void treeValueChanged(TreeSelectionEvent e) {
    }

    DefaultMutableTreeNode addNodes(DefaultMutableTreeNode top, File dir) {
        String curPath = dir.getPath();
        DefaultMutableTreeNode root = new DefaultMutableTreeNode(
                curPath.replace(getWorkPath(), ""));
        if (top != null) { // should only be null at root
            log("Adding curPath: " + root);
            top.add(root);
        }
        Vector<String> ol = new Vector<String>();
        String[] tmp = dir.list();
        for (String s : tmp) {
            log("Adding file: " + s);
            ol.addElement(s);
        }
        Collections.sort(ol, String.CASE_INSENSITIVE_ORDER);
        File file;
        Vector<String> files = new Vector<String>();
        // for dirs
        for (int i = 0; i < ol.size(); i++) {
            String filePath = ol.elementAt(i);
            String newPath;

            if (curPath.equals(".")) // if root
                newPath = filePath;
            else
                // not root
                newPath = curPath + File.separator + filePath;
            file = new File(newPath);
            log(String.format("cur: %s | file: %s | new: %s", curPath,
                    filePath, newPath));
            // if not a file then go inside folder and get files
            if (file.isDirectory())
                addNodes(root, file);
            else if (filePath.contains(".txt")) // txt files only
                files.addElement(filePath);

        }
        // for files
        for (int fnum = 0; fnum < files.size(); fnum++)
            root.add(new DefaultMutableTreeNode(files.elementAt(fnum).replace(getWorkPath(), ""), true));
        return root;
    }

    public void log(Object o) {
        System.out.println(o);
    }
}

Solution

  • The cause of your issue is here...

    if (curPath.equals(".")) // if root
        newPath = filePath;
    else
        // not root
        newPath = curPath + File.separator + filePath;
    

    Basically, what it's saying is, unless you are the root node, prefix curPath (which is dir.getPath()) to the filePath...which is why you get path/path in your tree...

    The entire if statement is pointless, based on what you want to achieve and be complete replace with...

    newPath = filePath;
    

    In face, you could get rid of newPath and simple use filePath directly...

    Updated

    Your core design is simply not capable of doing what it seems you are trying to achieve...

    Trying to maintain path information as Strings is overly complicated and error prone, it is much simpler to maintain the File reference, which provides you with all the information you need to render the file name and access the file for other purposes...the right tool for the job...

    Some background, the default TreeCellRenderer used by JTree simply uses the toString method of the object in the TreeModel to renderer something to the UI. In the case of DefaultMutableTreeNode, this simply uses the toString method of the userData object you pass it, so this means, when you do curPath.replace(getWorkPath(), ""), this is what eventually gets to the screen, but isn't what you want.

    Instead, you should be passing the actual File to the DefaultMutableTreeNode and using a custom TreeCellRenderer to modify the value going to the screen, for example...

    File Tree

    import java.awt.Color;
    import java.awt.Component;
    import java.awt.EventQueue;
    import java.io.File;
    import java.util.Collections;
    import java.util.Vector;
    
    import javax.swing.JFrame;
    import javax.swing.JScrollPane;
    import javax.swing.JTree;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.border.LineBorder;
    import javax.swing.event.TreeSelectionEvent;
    import javax.swing.event.TreeSelectionListener;
    import javax.swing.tree.DefaultMutableTreeNode;
    import javax.swing.tree.DefaultTreeCellRenderer;
    import javax.swing.tree.TreeSelectionModel;
    
    public class NGui {
    
        JFrame frame;
        private JTree tree;
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
                    new NGui();
                }
            });
        }
    
        public NGui() {
            initialize();
        }
    
        private void initialize() {
            frame = new JFrame();
    
            JScrollPane scrollPane = new JScrollPane();
            scrollPane.setBounds(10, 11, 212, 500);
            frame.getContentPane().add(scrollPane);
    
            tree = new JTree(addNodes(new File(getWorkPath())));
            tree.setRootVisible(false);
            tree.setShowsRootHandles(true);
    
            tree.setBorder(new LineBorder(new Color(0, 0, 0)));
            tree.getSelectionModel().setSelectionMode(
                    TreeSelectionModel.SINGLE_TREE_SELECTION);
            scrollPane.setViewportView(tree);
    
            tree.getSelectionModel().addTreeSelectionListener(
                    new TreeSelectionListener() {
                        @Override
                        public void valueChanged(TreeSelectionEvent e) {
                            treeValueChanged(e);
                        }
                    });
            tree.setCellRenderer(new FileTreeCellRenderer());
    
            frame.pack();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        private String getWorkPath() {
    //        return System.getProperty("user.home") + "\\Program Name\\";
            return ".";
        }
    
        private void treeValueChanged(TreeSelectionEvent e) {
        }
    
        public DefaultMutableTreeNode addNodes(File dir) {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(dir);
            for (File file : dir.listFiles()) {
                if (file.isDirectory()) {
                    node.add(addNodes(file));
                } else {
                    node.add(new DefaultMutableTreeNode(file));
                }
            }
            return node;
        }
    
        public class FileTreeCellRenderer extends DefaultTreeCellRenderer {
    
            @Override
            public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
                if (value instanceof DefaultMutableTreeNode) {
                    value = ((DefaultMutableTreeNode)value).getUserObject();
                    if (value instanceof File) {
                        value = ((File) value).getName();
                    }
                }
                return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
            }
    
        }
    
    }
    

    Take a look at Customizing a Tree's Display for more details