使用 FileTree 作为 TreeModel 扩展特定的 JTree 节点

Expanding specific JTree Node with FileTree as TreeModel

我正在尝试构建基于 JTree 的文件浏览器并尝试使用 setSelectionPathDefaultMutableTreeNode 导航到特定路径。

我参考了here

的代码
import java.io.File;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
import static javax.management.Query.value;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

public class FileSysBrowser extends JFrame {

    public JTree fileTree;
    private FileSystemModel fileSystemModel;
    static String REPO = "repo/dinesh/trunk";
    static String[] REPO_PATH = REPO.split("/", -1);
    static int repoPathIdx = 0;
    private JTextArea fileDetailsTextArea = new JTextArea();

    public FileSysBrowser(String directory) {
        System.out.println(Arrays.toString(REPO_PATH));
        setTitle("FileSysBrowser");
        fileDetailsTextArea.setEditable(false);
        fileSystemModel = new FileSystemModel(new File(directory));
        fileTree = new JTree(fileSystemModel);
        fileTree.setEditable(true);
        fileTree.addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(TreeSelectionEvent event) {
//                System.out.println(fileTree.getLastSelectedPathComponent());
//                File file = (File) fileTree.getLastSelectedPathComponent();
//                fileDetailsTextArea.setText(getFileDetails(file));
            }
        });
        getContentPane().add(new JScrollPane(fileTree));
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(640, 480);
        setVisible(true);
    }

    private DefaultMutableTreeNode buildNodeFromString(String path) {
        String[] s = path.split("/");
        File myFilePath = new File(path);

        DefaultMutableTreeNode node, lastNode = null, root = null;
        for (String str : s) {
            if (str.indexOf(":") != -1) {
                str = str.substring(0, str.indexOf(":"));
            }
            node = new DefaultMutableTreeNode(str);
            if (root == null) {
                root = node;
            }
            if (lastNode != null) {
                lastNode.add(node);
            }
            lastNode = node;
        }
        return root;
    }


    public static void main(String args[]) {

        FileSysBrowser fileSysBrowser = new FileSysBrowser("/");

        JTree jt = fileSysBrowser.fileTree;

//        jt.expandRow(21);
//        jt.expandRow(32);
//        TreePath pathForRow = jt.getPathForRow(4);
//        System.out.println(pathForRow);        
        DefaultMutableTreeNode node = fileSysBrowser.buildNodeFromString("repo/dinesh/trunk");

        TreePath pathForRow = new TreePath(node.getLastLeaf().getPath());
        System.out.println("pathForRow : " + pathForRow);
        jt.setSelectionPath(pathForRow);
    }
}

class FileSystemModel implements TreeModel {

    private File root;

    private final Vector listeners = new Vector();

    public FileSystemModel(File rootDirectory) {
        root = rootDirectory;
    }

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

    @Override
    public Object getChild(Object parent, int index) {
        File directory = (File) parent;
        String[] children = directory.list();
        Arrays.sort(children);
        String currentChild = children[index];
        return new TreeFile(directory, currentChild);
    }

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

    @Override
    public boolean isLeaf(Object node) {
        if (node.getClass() == DefaultMutableTreeNode.class) {
            DefaultMutableTreeNode dmtn = (DefaultMutableTreeNode) node;
            System.out.println("chidcount ->" + dmtn.getChildCount());
            System.out.println(dmtn.getChildCount()==0);
            return dmtn.getChildCount() == 0;
        } else {
            File file = (File) node;
            return file.isFile();
        }
    }

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

    }

    @Override
    public void valueForPathChanged(TreePath path, Object value) {
        File oldFile = (File) path.getLastPathComponent();
        String fileParentPath = oldFile.getParent();
        String newFileName = (String) value;
        File targetFile = new File(fileParentPath, newFileName);
        oldFile.renameTo(targetFile);
        File parent = new File(fileParentPath);
        int[] changedChildrenIndices = {getIndexOfChild(parent, targetFile)};
        Object[] changedChildren = {targetFile};
        fireTreeNodesChanged(path.getParentPath(), changedChildrenIndices, changedChildren);

    }

    private void fireTreeNodesChanged(TreePath parentPath, int[] indices, Object[] children) {
        TreeModelEvent event = new TreeModelEvent(this, parentPath, indices, children);
        Iterator iterator = listeners.iterator();
        TreeModelListener listener = null;
        while (iterator.hasNext()) {
            listener = (TreeModelListener) iterator.next();
            listener.treeNodesChanged(event);
        }
    }

    @Override
    public void addTreeModelListener(TreeModelListener listener) {
        listeners.add(listener);
    }

    @Override
    public void removeTreeModelListener(TreeModelListener listener) {
        listeners.remove(listener);
    }

    private class TreeFile extends File {

        public TreeFile(File parent, String child) {
            super(parent, child);
        }

        @Override
        public String toString() {
            return getName();
        }
    }
}

我刚刚在 isLeaf 中单独包含了支票。截至目前,它没有扩展路径。

只用expandRow,我就可以实现节点扩展。

我应该怎么做才能让它与 setSelectionPath 一起工作?

在探索 TreeModel 之后,我找到了解决方案。我已将 DefaultMutableTreeNode 扩展为 FileMutuableTreeNode,凡 DefaultMutableTreeNodeTreeModel 一起使用的地方,我已将其替换为 FileMutuableTreeNode。希望它对那些在不久的将来阅读这篇文章的人有用。

实际问题基于以下参考link。

参考: http://www.javaprogrammingforums.com/java-swing-tutorials/7944-how-use-jtree-create-file-system-viewer-tree.html

FileSysBrowser.java

//Reference : http://www.javaprogrammingforums.com/java-swing-tutorials/7944-how-use-jtree-create-file-system-viewer-tree.html
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JButton;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

public class FileSysBrowser extends JFrame {

    public JTree fileTree;
    private FileSystemModel fileSystemModel;

    public FileSysBrowser(String directory) {
//        System.out.println("REPO : " + Arrays.toString(REPO_PATH));
        setTitle("FileSysBrowser");
        fileSystemModel = new FileSystemModel(new FileMutableTreeNode(new File(directory)));
        fileTree = new JTree(fileSystemModel);
        fileTree.setEditable(false);
        JPanel pnlMain = new JPanel(new BorderLayout(5, 5));
        pnlMain.add(new JScrollPane(fileTree), BorderLayout.CENTER);
        final JButton btn = new JButton("click");
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new Thread() {
                    @Override
                    public void run() {
                        btn.setEnabled(false);
                        expandNodePath("/repo/dinesh/trunk/Design/");
                        btn.setEnabled(true);
                    }
                }.start();

            }
        });
        pnlMain.add(btn, BorderLayout.PAGE_END);
        getContentPane().add(pnlMain);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(640, 480);
        setVisible(true);
    }
//Reference :  
//Thanks to 'trashgod' for the answer    
    private FileMutableTreeNode findNode(FileMutableTreeNode root, String s) {
        @SuppressWarnings("unchecked")
        Enumeration<FileMutableTreeNode> e = root.depthFirstEnumeration();
        while (e.hasMoreElements()) {
            FileMutableTreeNode node = e.nextElement();
            if (node.toString().equals(s)) {
//                return new TreePath(node.getPath());
                return node;
            }
        }
        return null;
    }

    private void expandNodePath(String filePath) {
        if(filePath.startsWith("/")) {
            filePath = filePath.replaceFirst("/", "");
        }
        String[] files = filePath.split("/");
        //Initializing the parent node as 'root'
        FileMutableTreeNode parentNode = fileSystemModel.getRoot();
        for (String file : files) {
            FileMutableTreeNode childNode = findNode(parentNode, file);
            fileTree.expandPath(new TreePath(childNode.getPath()));
            // Then setting the current 'child' node as parent node 
            // for the next iteration
            parentNode = childNode;
        }

//  The below code is what the expansion of above for loop code. 
//  For ease of understanding, I have kept it for others. 
//        FileMutableTreeNode repoNode = findNode(fileSystemModel.getRoot(), "repo");
//        fileTree.expandPath(new TreePath(repoNode.getPath()));
//        FileMutableTreeNode dineshNode = findNode(repoNode, "dinesh");
//        fileTree.expandPath(new TreePath(dineshNode.getPath()));

    }

    public static void main(String args[]) {
//        System.out.println(new File("/").getName());

        FileSysBrowser fileSysBrowser = new FileSysBrowser("/");

        JTree jt = fileSysBrowser.fileTree;

        jt.addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(TreeSelectionEvent e) {
                TreePath tp = e.getNewLeadSelectionPath();
                if (tp != null) {
                    System.out.println(tp);
//                    System.out.println(tp.getLastPathComponent());
                }
            }
        });
    }
}

class FileSystemModel implements TreeModel {

//    private File root;
    private FileMutableTreeNode root;

    private final Vector listeners = new Vector();

    public FileSystemModel(FileMutableTreeNode rootDirectory) {
        root = rootDirectory;
    }

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

    @Override
    public Object getChild(Object parent, int index) {

        FileMutableTreeNode parentNode = (FileMutableTreeNode) parent;
        File directory = parentNode.getFileNode();
        String[] children = directory.list();
        Arrays.sort(children);
        String currentChild = children[index];
        FileMutableTreeNode childNode = new FileMutableTreeNode(new File(directory, currentChild));
        if (parentNode.toString().equals("/")) {
            root.add(childNode);
        } else {
            parentNode.add(childNode);
        }
        return childNode;
    }

    @Override
    public int getChildCount(Object parent) {
        FileMutableTreeNode fileNode = (FileMutableTreeNode) parent;
        File file = fileNode.getFileNode();
        if (file.isDirectory()) {
            String[] fileList = file.list();
            if (fileList != null) {
                return file.list().length;
            }
        }
        return 0;
    }

    @Override
    public boolean isLeaf(Object node) {
        FileMutableTreeNode fileNode = (FileMutableTreeNode) node;
        File file = fileNode.getFileNode();
        return file.isFile();
    }

    @Override
    public int getIndexOfChild(Object parent, Object child) {
        FileMutableTreeNode parentNode = (FileMutableTreeNode) parent;
        File directory = parentNode.getFileNode();
        FileMutableTreeNode childNode = (FileMutableTreeNode) child;
        File file = childNode.getFileNode();
        String[] children = directory.list();
        for (int i = 0; i < children.length; i++) {
            if (file.getName().equals(children[i])) {
                return i;
            }
        }
        return -1;

    }

    @Override
    public void valueForPathChanged(TreePath path, Object value) {
        System.out.println("valueForPathChanged -> path : " + path + ", value : " + value);
    }

    @Override
    public void addTreeModelListener(TreeModelListener listener) {
        listeners.add(listener);
    }

    @Override
    public void removeTreeModelListener(TreeModelListener listener) {
        listeners.remove(listener);
    }

}

FileMutableTreeNode .java

import java.io.File;
import javax.swing.tree.DefaultMutableTreeNode;

class FileMutableTreeNode extends DefaultMutableTreeNode {

    private File fileNode = null;

    public FileMutableTreeNode(File fileNode) {
        this.fileNode = fileNode;
    }

    public File getFileNode() {
        return fileNode;
    }

    @Override
    public String toString() {
        //For root, returning the name as '/'
        if (fileNode.getAbsolutePath().equals("/")) {
            return "/";
        } else {
            return fileNode.getName();
        }
    }
}