Java Jtree Directory Structure from File Paths

Java JTree directory structure from file paths

Let File do the work of parsing and maintaining paths. As you want to display the files in a JTree, you might as well create a corresponding TreeModel such as FileTreeModel, cited here. Because it implements TreeModel, it can "be set as a JTree's model and then you'd have a plain old standard JTree." You can use any File in any mounted file system as the root, for example:

TreeModel model = new FileTreeModel(new File(System.getProperty("user.dir")));
JTree tree = new JTree(model);

image

Java JTree from directory (shows full path instead of just the name of the file)

import java.io.File;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.WindowConstants;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

class FileTreeModel implements TreeModel {
private final ArrayList<TreeModelListener> mListeners = new ArrayList<>();
private final MyFile mFile;

public FileTreeModel(final MyFile pFile) {
mFile = pFile;
}
@Override public Object getRoot() {
return mFile;
}
@Override public Object getChild(final Object pParent, final int pIndex) {
return ((MyFile) pParent).listFiles()[pIndex];
}
@Override public int getChildCount(final Object pParent) {
return ((MyFile) pParent).listFiles().length;
}
@Override public boolean isLeaf(final Object pNode) {
return !((MyFile) pNode).isDirectory();
}
@Override public void valueForPathChanged(final TreePath pPath, final Object pNewValue) {
final MyFile oldTmp = (MyFile) pPath.getLastPathComponent();
final File oldFile = oldTmp.getFile();
final String newName = (String) pNewValue;
final File newFile = new File(oldFile.getParentFile(), newName);
oldFile.renameTo(newFile);
System.out.println("Renamed '" + oldFile + "' to '" + newFile + "'.");
reload();
}
@Override public int getIndexOfChild(final Object pParent, final Object pChild) {
final MyFile[] files = ((MyFile) pParent).listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i] == pChild) return i;
}
return -1;
}
@Override public void addTreeModelListener(final TreeModelListener pL) {
mListeners.add(pL);
}
@Override public void removeTreeModelListener(final TreeModelListener pL) {
mListeners.remove(pL);
}

/**
* stolen from http://developer.classpath.org/doc/javax/swing/tree/DefaultTreeModel-source.html
*
* <p>
* Invoke this method if you've modified the TreeNodes upon which this model
* depends. The model will notify all of its listeners that the model has
* changed. It will fire the events, necessary to update the layout caches and
* repaint the tree. The tree will <i>not</i> be properly refreshed if you
* call the JTree.repaint instead.
* </p>
* <p>
* This method will refresh the information about whole tree from the root. If
* only part of the tree should be refreshed, it is more effective to call
* {@link #reload(TreeNode)}.
* </p>
*/
public void reload() {
// Need to duplicate the code because the root can formally be
// no an instance of the TreeNode.
final int n = getChildCount(getRoot());
final int[] childIdx = new int[n];
final Object[] children = new Object[n];

for (int i = 0; i < n; i++) {
childIdx[i] = i;
children[i] = getChild(getRoot(), i);
}

fireTreeStructureChanged(this, new Object[] { getRoot() }, childIdx, children);
}

/**
* stolen from http://developer.classpath.org/doc/javax/swing/tree/DefaultTreeModel-source.html
*
* fireTreeStructureChanged
*
* @param source the node where the model has changed
* @param path the path to the root node
* @param childIndices the indices of the affected elements
* @param children the affected elements
*/
protected void fireTreeStructureChanged(final Object source, final Object[] path, final int[] childIndices, final Object[] children) {
final TreeModelEvent event = new TreeModelEvent(source, path, childIndices, children);
for (final TreeModelListener l : mListeners) {
l.treeStructureChanged(event);
}
}
}

class MyFile {
private final File mFile;

public MyFile(final File pFile) {
mFile = pFile;
}

public boolean isDirectory() {
return mFile.isDirectory();
}

public MyFile[] listFiles() {
final File[] files = mFile.listFiles();
if (files == null) return null;
if (files.length < 1) return new MyFile[0];

final MyFile[] ret = new MyFile[files.length];
for (int i = 0; i < ret.length; i++) {
final File f = files[i];
ret[i] = new MyFile(f);
}
return ret;
}

public File getFile() {
return mFile;
}

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

public class FileWrapperDeluxe {
public static void main(final String[] args) {
final JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
f.setBounds(100, 100, 400, 400);

final File file = new File("E:\\");
final MyFile mf = new MyFile(file);
final TreeModel model = new FileTreeModel(mf);

final JTree tree = new JTree(model);
tree.setEditable(true);

f.add(new JScrollPane(tree));
f.setVisible(true);
}
}

Java Tree to represent filesystem (files/dir) from list of paths

Thank you for all your answer. I made my working implementation.
I think that I will need to improve it in order to make it works better with more caching in adding element to the tree structure.

As I said what I was needing was a structure that allow me to have a "virtual" rappresentation of a FS.

MXMTree.java

public class MXMTree {

MXMNode root;
MXMNode commonRoot;

public MXMTree( MXMNode root ) {
this.root = root;
commonRoot = null;
}

public void addElement( String elementValue ) {
String[] list = elementValue.split("/");

// latest element of the list is the filename.extrension
root.addElement(root.incrementalPath, list);

}

public void printTree() {
//I move the tree common root to the current common root because I don't mind about initial folder
//that has only 1 child (and no leaf)
getCommonRoot();
commonRoot.printNode(0);
}

public MXMNode getCommonRoot() {
if ( commonRoot != null)
return commonRoot;
else {
MXMNode current = root;
while ( current.leafs.size() <= 0 ) {
current = current.childs.get(0);
}
commonRoot = current;
return commonRoot;
}

}

}

MXMNode.java

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MXMNode {

List<MXMNode> childs;
List<MXMNode> leafs;
String data;
String incrementalPath;

public MXMNode( String nodeValue, String incrementalPath ) {
childs = new ArrayList<MXMNode>();
leafs = new ArrayList<MXMNode>();
data = nodeValue;
this. incrementalPath = incrementalPath;
}

public boolean isLeaf() {
return childs.isEmpty() && leafs.isEmpty();
}

public void addElement(String currentPath, String[] list) {

//Avoid first element that can be an empty string if you split a string that has a starting slash as /sd/card/
while( list[0] == null || list[0].equals("") )
list = Arrays.copyOfRange(list, 1, list.length);

MXMNode currentChild = new MXMNode(list[0], currentPath+"/"+list[0]);
if ( list.length == 1 ) {
leafs.add( currentChild );
return;
} else {
int index = childs.indexOf( currentChild );
if ( index == -1 ) {
childs.add( currentChild );
currentChild.addElement(currentChild.incrementalPath, Arrays.copyOfRange(list, 1, list.length));
} else {
MXMNode nextChild = childs.get(index);
nextChild.addElement(currentChild.incrementalPath, Arrays.copyOfRange(list, 1, list.length));
}
}
}

@Override
public boolean equals(Object obj) {
MXMNode cmpObj = (MXMNode)obj;
return incrementalPath.equals( cmpObj.incrementalPath ) && data.equals( cmpObj.data );
}

public void printNode( int increment ) {
for (int i = 0; i < increment; i++) {
System.out.print(" ");
}
System.out.println(incrementalPath + (isLeaf() ? " -> " + data : "") );
for( MXMNode n: childs)
n.printNode(increment+2);
for( MXMNode n: leafs)
n.printNode(increment+2);
}

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

}

Test.java for test code

public class Test {

/**
* @param args
*/
public static void main(String[] args) {

String slist[] = new String[] {
"/mnt/sdcard/folder1/a/b/file1.file",
"/mnt/sdcard/folder1/a/b/file2.file",
"/mnt/sdcard/folder1/a/b/file3.file",
"/mnt/sdcard/folder1/a/b/file4.file",
"/mnt/sdcard/folder1/a/b/file5.file",
"/mnt/sdcard/folder1/e/c/file6.file",
"/mnt/sdcard/folder2/d/file7.file",
"/mnt/sdcard/folder2/d/file8.file",
"/mnt/sdcard/file9.file"
};

MXMTree tree = new MXMTree(new MXMNode("root", "root"));
for (String data : slist) {
tree.addElement(data);
}

tree.printTree();
}

}

Please tell me if you have some good advice about improvments :)

How to display full file path in JTree?

The fix seen here is in two parts, marked by /* new */. Basically:

  • Change the FileNode to add a getFile() method (not strictly necessary, but good encapsulation).
  • Get the FileNode from the DefaultMutableTreeNode, then get the File from that.

import java.io.File;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

public class NewerFileTree extends JPanel implements Runnable {

protected static final String File = null;
private DefaultMutableTreeNode root;
private DefaultTreeModel treeModel;
private JTree tree;

public void run() {
JFrame frame = new JFrame("File Browser");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

File fileRoot = new File("C://");
root = new DefaultMutableTreeNode(new FileNode(fileRoot));
treeModel = new DefaultTreeModel(root);

tree = new JTree(treeModel);
tree.setShowsRootHandles(true);
JScrollPane scrollPane = new JScrollPane(tree);

tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent event) {
/* new */
DefaultMutableTreeNode dmtn = (DefaultMutableTreeNode)
tree.getLastSelectedPathComponent();
FileNode fileNode = (FileNode)dmtn.getUserObject();
File file = fileNode.getFile();
System.out.println(file);
}
});

frame.add(scrollPane);
frame.setLocationByPlatform(true);
frame.setSize(640, 480);
frame.setVisible(true);

CreateChildNodes ccn = new CreateChildNodes(fileRoot, root);
new Thread(ccn).start();
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new NewerFileTree());
}

public class CreateChildNodes implements Runnable {

private DefaultMutableTreeNode root;
private File fileRoot;

public CreateChildNodes(File fileRoot,
DefaultMutableTreeNode root) {
this.fileRoot = fileRoot;
this.root = root;
}

public void run() {
createChildren(fileRoot, root);
}

private void createChildren(File fileRoot,
DefaultMutableTreeNode node) {
File[] files = fileRoot.listFiles();
if (files == null) {
return;
}

for (File file : files) {
DefaultMutableTreeNode childNode
= new DefaultMutableTreeNode(new FileNode(file));

DefaultMutableTreeNode childNodes = new DefaultMutableTreeNode("hello");
node.add(childNode);
if (file.isDirectory()) {
createChildren(file, childNode);
}
}
}
}

public class FileNode {

private File file;

public FileNode(File file) {
this.file = file;
}

/* new */
public File getFile() {
return file;
}

@Override
public String toString() {
String name = file.getName();
if (name.equals("")) {
return file.getAbsolutePath();
} else {
return name;
}
}
}
}

Display file(s) name and select it under the folder in JTree

Don't add all the file names in a loop. Instead, create a FileTreeModel that implements TreeModel, as shown here. The implementation simply invokes the File method listFiles() in getChild() and getIndexOfChild(). Then you can create a tree and expand any desired row; use setSelectionPath() as shown here.

TreeModel model = new FileTreeModel(new File(System.getProperty("user.dir")));
JTree tree = new JTree(model);
tree.expandRow(0);

image

I get only the c:\; please give me directions to get all the system drives, etc.

You can get a list of filesystem roots with File.listRoots(), as shown in Find all drive letters in Java, or FileSystemView#getRoots(), as shown in File Browser GUI.

Creating dynamic JTree from absolute file path

Thanks all for your help. Basically I wanted to represent file system from the path which i retrieve from database. Files/directories are not actually stored on database but are dynamically generated from absolute/relative path.

I found answer here...

Java Tree to represent filesystem (files/dir) from list of paths



Related Topics



Leave a reply



Submit