Okay so I used the second block of code from this website http://www.java2s.com/Tutorials/Java/JavaFX/0660__JavaFX_Tree_View.htm where it states "The following code create a dynamic tree from the local file system"
I do not understand how this code works in order to customise it to my needs. Particularly the overriding methods, there did not seem to be a place where I could add in "only add folders down to the sub directory which contain mp3 files". I reckon it's likely going to require something more complex such as something that goes through and removes folders. I'm honestly not sure.
I have tried to use this code in my program which is to show mp3 files. The idea was to have two treeViews side by side, the left side shows the hierarchy of folders to the folders which have mp3 files in them (and do not shows other folders which do not have mp3 files in them) and the right side shows files which are of only mp3 file type in those folders. There is a screenshot further down.
This is the code I have so far which returns a TreeView in a VBox. There are two segments of code which are commented out. The first is due to the fact that java: search file according to its name in directory and subdirectories does not wish to search my C: drive. (I do not know why). So I changed it to only scan my D: (Partition drive). The second is from the webpage where I got the main segment of code. This code was moved to an outer class which handles. As well as a cheeky bit of code to handle more than one drive.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.VBox;
import org.apache.commons.io.FileUtils;
/**
* https://stackoverflow.com/questions/6251762/java-search-file-according-to-its-name-in-directory-and-subdirectories
* https://stackoverflow.com/questions/26690247/how-to-make-directories-expandable-in-javafx-treeview
* http://www.java2s.com/Tutorials/Java/JavaFX/0660__JavaFX_Tree_View.htm
*
* @author Scorchgid
*/
public class FolderTreeView {
int x = 0;
private final String fileName = ".mp3";
private MainView mainView;
private TreeView<File> treeViewFile = new TreeView<>();
public TreeView<File> getTreeViewFile() {
return treeViewFile;
}
public void setTreeViewFile(TreeView<File> treeViewFile) {
this.treeViewFile = treeViewFile;
}
public VBox treeStack() throws IOException {
VBox vbox = new VBox();
File[] drives = File.listRoots();
ArrayList<File> fileListing;
/*for (File dir : drives) {
System.out.println(dir.toString());
fileListing = restrictingList(dir);
}*/
fileListing = restrictingList(new File("D:\\"));
ArrayList<TreeItem> treeItems = new ArrayList<>();
for (File dir : drives) {
//System.out.println(dir.toString());
treeItems.add(createNode(dir));
}
TreeView<File> tree = proxyCreateNode(treeItems);
vbox.getChildren().add(tree);
return vbox;
}
// https://stackoverflow.com/questions/22260032/set-two-root-nodes-for-treeview
public TreeView<File> proxyCreateNode(ArrayList<TreeItem> arrayListTreeItem) {
TreeItem<File> proxyItem = new TreeItem<>();
proxyItem.setExpanded(true);
for (TreeItem<File> item : arrayListTreeItem) {
proxyItem.getChildren().addAll(item);
}
TreeView<File> tree = new TreeView<>(proxyItem);
tree.setShowRoot(false);
return tree;
}
private ArrayList<File> restrictingList(File root) {
ArrayList<File> fileArray = new ArrayList<>();
boolean recursive = true;
Collection files = FileUtils.listFiles(root, null, recursive);
for (Iterator iterator = files.iterator(); iterator.hasNext();) {
File file = (File) iterator.next();
if (file.getName().endsWith(fileName)) {
fileArray.add(file);
}
}
return fileArray;
}
/* @Override
public void start(Stage stage) {
Scene scene = new Scene(new Group(), 300, 300);
TreeItem<File> root = createNode(new File("c:/"));
TreeView treeView = new TreeView<File>(root);
vbox.getChildren().add(treeView);
((Group) scene.getRoot()).getChildren().add(vbox);
stage.setScene(scene);
stage.show();
}
*/
private TreeItem<File> createNode(final File f) {
return new TreeItem<File>(f) {
private boolean isLeaf;
private boolean isFirstTimeChildren = true;
private boolean isFirstTimeLeaf = true;
@Override
public ObservableList<TreeItem<File>> getChildren() {
if (isFirstTimeChildren) {
isFirstTimeChildren = false;
super.getChildren().setAll(buildChildren(this));
}
return super.getChildren();
}
@Override
public boolean isLeaf() {
if (isFirstTimeLeaf) {
isFirstTimeLeaf = false;
File f = (File) getValue();
isLeaf = f.isFile();
}
return isLeaf;
}
private ObservableList<TreeItem<File>> buildChildren(
TreeItem<File> TreeItem) {
File f = TreeItem.getValue();
if (f == null) {
return FXCollections.emptyObservableList();
}
if (f.isFile()) {
return FXCollections.emptyObservableList();
}
File[] files = f.listFiles();
if (files != null) {
ObservableList<TreeItem<File>> children = FXCollections
.observableArrayList();
for (File childFile : files) {
//System.out.println("Adding " + childFile.getAbsolutePath());
if (childFile.isDirectory()) {
children.add(createNode(childFile));
}
}
return children;
}
return FXCollections.emptyObservableList();
}
};
}
}
You can create the tree structure recursively. There are various mechanisms (please also note jewelsea's comment to your question), here's one:
Then you have a tree with all of your files. Since you intend to scan the entire tree structure from a given root path and keep it in memory, you may as well simply filter the tree. I took the code above and the filter code from rli's answer in this post and adapted it. It basically creates a filtered tree structure from the original structure.
Here's the full example code:
Simply enter search text in the text field, the tree will be filtered accordingly.
You may change the toString() method if you'd like to see the full path. Also, currently a substring is searched instead of the file extension. That's just for demo, adapting it for your needs is trivial.
Similar mechanism applies if you'd like to display parts of the tree in another tree view or list view.
Example if you'd like to get a tree structure with all nodes that contain a file with e. g. substring "mp3" in the text filter while not displaying the file itself in the tree, here's the modified version of the filter method:
If you'd like to do it the performing / memory efficient way, you could take a look at the TreeItem example code which will scan a folder only when you navigate into it.