如何在文件系统内容的 JTree 中插入和显示新节点

问题描述 投票:0回答:1

我已经成功创建了一个小程序,它将在 JTree 中显示文件系统内容。它按设计仅显示文件夹和纯文本文件。我现在想在创建树时将文件夹添加到树中。示例程序将显示树并创建一个文件夹,但不会为刚刚创建的文件夹插入新节点。创建文件夹时如何将节点插入树中并使树显示新文件夹?

非常感谢!

该类创建并显示树。

import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

public class TreeFrame extends JFrame{

    private JTree fileTree = null;
    private String USER_HOME = System.getProperty("user.home");

    public TreeFrame(){
        super("File Tree");
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        //Create tree
        DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(new File(USER_HOME));
        fileTree = new JTree(new FileTreeModelTest(rootNode));
        fileTree.setCellRenderer(new TreeCellRendererTest());
        fileTree.addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(TreeSelectionEvent e) {
                //Commented out the next part because it causes a null pointer exception.
                //I believe it is caused by the tree not inserting a node.
                //JTree tree = (JTree)e.getSource();
                //DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
                //Object obj = node.getUserObject();//Causes a null pointer exception
                //if(obj instanceof File){
                //    File f = (File)node.getUserObject();
                //    System.out.println(f.getAbsolutePath());
                //}
            }
        });

        JPanel panel = new JPanel();
        JLabel folderLabel = new JLabel("Name:");
        panel.add(folderLabel, BorderLayout.WEST);
        final JTextField textField = new JTextField(25);
        textField.setPreferredSize(new Dimension(100, 28));
        panel.add(textField, BorderLayout.CENTER);
        JButton button = new JButton("Create Foder");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                //Add a folder when the menu item is clicked
                DefaultMutableTreeNode node = (DefaultMutableTreeNode)fileTree.getLastSelectedPathComponent();
                File f = (File)node.getUserObject();
                if(f.isDirectory()){
                    File dir = new File(f.getAbsolutePath()+"/"+textField.getText().trim());

                    if(dir.mkdirs()){
                        System.out.println("ADDED: " + dir.getAbsolutePath());

                        //Insert node into tree model -- this is the part that does not seem to work.
                        FileTreeModelTest model = (FileTreeModelTest)fileTree.getModel();
                        DefaultMutableTreeNode child = new DefaultMutableTreeNode(dir);
                        model.insertNodeInto(child, node, node.getChildCount());
                        model.reload(node);
                        TreeNode[] nodes = model.getPathToRoot(child);
                        TreePath path = new TreePath(nodes);
                        fileTree.scrollPathToVisible(path);
                        fileTree.setSelectionPath(path);

                    }

                }
            }
        });
        panel.add(button, BorderLayout.EAST);
        getContentPane().add(panel, BorderLayout.NORTH);

        JScrollPane scrollPane = new JScrollPane(fileTree);
        scrollPane.setPreferredSize(new Dimension(200, 400));

        getContentPane().add(scrollPane, BorderLayout.CENTER);
        pack();

    }

    public static void main(String[] args){
        TreeFrame frame = new TreeFrame();
        frame.setVisible(true);
    }

}

这个类是树模型。

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import java.io.File;
import java.io.FileFilter;
import java.util.Arrays;

public class FileTreeModelTest extends DefaultTreeModel {

    public FileTreeModelTest(DefaultMutableTreeNode root){
            super(root);
        }

        private File[] getFiles(File parent){
            File[] f = parent.listFiles(new FileFilter() {
                @Override
                public boolean accept(File file) {
                    if(file==null)
                        return false;
                    if(file.isDirectory())
                        return true;
                    if(file.getName().toLowerCase().endsWith("txt")){
                        return true;
                    }
                    return false;
                }
            });
            return f;
        }

        @Override
        public Object getChild(Object parent, int index){
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)parent;
            File p = (File)node.getUserObject();
            File[] pFile = getFiles(p);
            DefaultMutableTreeNode child = new DefaultMutableTreeNode(pFile[index]);
            return child;
        }

        @Override
        public int getChildCount(Object parent){
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)parent;
            File f = (File)node.getUserObject();
            if(!f.isDirectory()){
                return 0;
            }else{
                //Is a directory, return number of folders and text files
                File[] children = getFiles(f);
                if(children==null) return 0;
                return children.length;
            }
        }

        @Override
        public int getIndexOfChild(Object parent, Object child){
            DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)parent;
            DefaultMutableTreeNode childNode = (DefaultMutableTreeNode)child;
            File p = (File)parentNode.getUserObject();
            File c = (File)childNode.getUserObject();

            File[] pFile = getFiles(p);
            return Arrays.asList(pFile).indexOf(c);
        }

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

        @Override
        public boolean isLeaf(Object parent){
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)parent;
            File f = (File)node.getUserObject();
            if(f.isDirectory()){
                File[] children = getFiles(f);
                if(children==null) return true;
                //F is a directory. If it has no files, then it is a leaf.
                return children.length==0;
            }else{
                //F is a file. It is a leaf.
                return true;
            }
        }

}

最后一个类是树单元渲染器。

import javax.swing.*;
import javax.swing.filechooser.FileSystemView;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;
import java.io.File;

public class TreeCellRendererTest extends DefaultTreeCellRenderer {

    private FileSystemView fsv = FileSystemView.getFileSystemView();

    public TreeCellRendererTest(){

    }

    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
            super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);

            if(value instanceof DefaultMutableTreeNode){
                Object obj = ((DefaultMutableTreeNode) value).getUserObject();

                if(obj instanceof File){
                    File f = (File)obj;
                    if(row==0){
                        setIcon(fsv.getSystemIcon(f));
                        setText(f.getPath());
                    }else
                    if(f.isFile()){
                        setIcon(fsv.getSystemIcon(f));
                        setText(f.getName());
                    }else{
                        setIcon(fsv.getSystemIcon(f));
                        setText(f.getName());
                    }
                }
            }

            return this;
        }


}
java swing jtree defaulttreemodel
1个回答
0
投票

方法似乎存在基本的不匹配。您正在使用

DefaultMutableTreeNode
,它缓存子节点,但直接通过模型管理实际节点,这会在多个不同级别引起混乱......

如果您想继续直接监视磁盘内容(或代理它),我将创建一个自定义

TreeNode
,其唯一职责是监视单个目录。

然后,我将创建一个自定义

TreeModel
(可能来自
DefaultTreeModel
),它提供了
makeDirectory
方法,您可以传递当前选择的
TreeNode
和目录名称。

此方法将负责目录的物理创建以及对

JTree
的结构更改的通知(通过
nodesWereInserted
方法)。我可能会让这个节点返回一个代表子节点的实例 a
TreeNode
...

这种方法存在很多问题,特别是对象的引用。在您当前的方法中,每当调用

DefaultMutableTreeNode
时,您都会创建一个新的
getChild
,如果 API 的某些部分依赖于给定位置/数据保持不变的那些引用,这可能会导致问题,这将需要您维护一些一种内部缓存,将
File
TreeNode
链接起来...这违背了目的...

更好的方法可能是利用现有的“可变树节点”API,每个节点仍然负责单个

File
,但它也会缓存结果。这里的问题是管理何时应该填充节点(因为您不想填充未展开的目录节点)。

如果您计划使用“Watch Service”API,那么我会选择“可变树节点”API 并缓存其中的子文件(根据需要),这将简化问题...

© www.soinside.com 2019 - 2024. All rights reserved.