我已经成功创建了一个小程序,它将在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;
}
}
答案 0 :(得分:0)
似乎存在基本的不匹配方法。您正在使用DefaultMutableTreeNode
来缓存子节点,但是直接通过模型管理实际节点,这会导致多个不同级别的混淆......
如果要继续直接监视磁盘内容(或代理它),我会创建一个自定义TreeNode
,其唯一责任是监视单个目录。
然后我会创建一个自定义TreeModel
(可能来自DefaultTreeModel
),它提供了makeDirectory
方法,您可以通过当前选定的TreeNode
和名称目录。
然后,此方法将负责物理创建目录并通知JTree
的结构更改(通过nodesWereInserted
方法)。我可能让这个节点返回一个代表孩子的实例TreeNode
......
这种方法存在很多问题,很难引用对象。在您当前的方法中,无论何时调用DefaultMutableTreeNode
,您都会创建一个新的getChild
,如果API的某些部分依赖于那些对给定位置/数据保持不变的引用,这可能会导致问题,这将需要你要维护某种内部缓存,将File
与TreeNode
联系起来......这种目的会失败......
更好的方法可能是利用现有的“可变树节点”API,每个节点仍然负责单个File
,但它也会缓存结果。这里的问题是管理何时应该填充节点(因为您不想填充未展开的目录节点)。
我打算使用“Watch Service”API,然后我会选择“可变树节点”API并在其中缓存子文件(根据需要),它只是问题......