好的,所以我使用了本网站的第二块代码 http://www.java2s.com/Tutorials/Java/JavaFX/0660__JavaFX_Tree_View.htm其中声明“以下代码从本地文件系统创建动态树”
我不明白这段代码是如何工作的,以便根据我的需要进行自定义。特别是最重要的方法,似乎没有一个地方我可以添加“只添加文件夹到包含mp3文件的子目录”。我认为它可能需要一些更复杂的东西,比如经历的东西和删除文件夹。老实说,我不确定。
我试图在我的程序中使用此代码来显示mp3文件。想法是并排放置两个treeView,左侧显示文件夹的层次结构,其中包含mp3文件的文件夹(并且不显示其中没有mp3文件的其他文件夹),右侧显示文件这些文件夹中只有mp3文件类型。还有一个屏幕截图。
这是我到目前为止的代码,它返回一个VBox中的TreeView。 有两段代码被注释掉了。第一个是由于java: search file according to its name in directory and subdirectories不希望搜索我的C:驱动器。 (我不知道为什么)。所以我把它改成只扫描我的D :(分区驱动器)。第二个是从我获得主要代码段的网页。此代码被移动到处理的外部类。以及处理多个驱动器的一些代码。
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();
}
};
}
}
答案 0 :(得分:0)
您可以递归地创建树结构。有各种机制(请注意jewelsea对你的问题的评论),这里有一个:
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.function.Function;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class FolderTreeView extends Application {
private static final String ROOT_FOLDER = "c:/music"; // TODO: change or make selectable
@Override
public void start(Stage primaryStage) throws IOException {
// create root
TreeItem<Path> treeItem = new TreeItem<Path>(Paths.get( ROOT_FOLDER));
treeItem.setExpanded(true);
// create tree structure
createTree( treeItem);
// sort tree structure by name
treeItem.getChildren().sort( Comparator.comparing( new Function<TreeItem<Path>, String>() {
@Override
public String apply(TreeItem<Path> t) {
return t.getValue().toString().toLowerCase();
}
}));
// create components
TreeView<Path> treeView = new TreeView<Path>(treeItem);
StackPane root = new StackPane();
root.getChildren().add(treeView);
primaryStage.setScene(new Scene(root, 1024, 768));
primaryStage.setTitle("Folder Tree View Example");
primaryStage.show();
}
/**
* Recursively create the tree
* @param rootItem
* @throws IOException
*/
public static void createTree(TreeItem<Path> rootItem) throws IOException {
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(rootItem.getValue())) {
for (Path path : directoryStream) {
TreeItem<Path> newItem = new TreeItem<Path>(path);
newItem.setExpanded(true);
rootItem.getChildren().add(newItem);
if (Files.isDirectory(path)) {
createTree(newItem);
}
}
}
}
public static void main(String[] args) {
launch(args);
}
}
然后你有一个包含所有文件的树。由于您打算从给定的根路径扫描整个树结构并将其保留在内存中,因此您也可以简单地过滤树。我从this post中的rli的答案中获取了上面的代码和过滤器代码并对其进行了调整。它基本上从原始结构创建一个过滤树结构。
以下是完整的示例代码:
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.function.Function;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class FolderTreeViewWithFilter extends Application {
private static final String ROOT_FOLDER = "c:/music"; // TODO: change or make selectable
TreeItem<FilePath> rootTreeItem;
TreeView<FilePath> treeView;
@Override
public void start(Stage primaryStage) throws IOException {
// root component
VBox root = new VBox();
// filter
TextField filter = new TextField();
filter.textProperty().addListener((observable, oldValue, newValue) -> filterChanged(newValue));
// treeview
treeView = new TreeView<FilePath>();
VBox.setVgrow(treeView, Priority.ALWAYS);
root.getChildren().addAll( filter, treeView);
// stage
primaryStage.setScene(new Scene(root, 1024, 768));
primaryStage.setTitle("Folder Tree View With Filter Example");
primaryStage.show();
// create tree
createTree();
// show tree structure in tree view
treeView.setRoot(rootTreeItem);
}
/**
* Create original tree structure
* @throws IOException
*/
private void createTree() throws IOException {
// create root
rootTreeItem = createTreeRoot();
// create tree structure recursively
createTree( rootTreeItem);
// sort tree structure by name
rootTreeItem.getChildren().sort( Comparator.comparing( new Function<TreeItem<FilePath>, String>() {
@Override
public String apply(TreeItem<FilePath> t) {
return t.getValue().toString().toLowerCase();
}
}));
}
/**
* Iterate through the directory structure and create a file tree
* @param rootItem
* @throws IOException
*/
public static void createTree(TreeItem<FilePath> rootItem) throws IOException {
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(rootItem.getValue().getPath())) {
for (Path path : directoryStream) {
TreeItem<FilePath> newItem = new TreeItem<FilePath>( new FilePath( path));
newItem.setExpanded(true);
rootItem.getChildren().add(newItem);
if (Files.isDirectory(path)) {
createTree(newItem);
}
}
}
// catch exceptions, e. g. java.nio.file.AccessDeniedException: c:\System Volume Information, c:\$RECYCLE.BIN
catch( Exception ex) {
ex.printStackTrace();
}
}
/**
* Create new filtered tree structure
* @param root
* @param filter
* @param filteredRoot
*/
private void filter(TreeItem<FilePath> root, String filter, TreeItem<FilePath> filteredRoot) {
for (TreeItem<FilePath> child : root.getChildren()) {
TreeItem<FilePath> filteredChild = new TreeItem<>( child.getValue());
filteredChild.setExpanded(true);
filter(child, filter, filteredChild );
if (!filteredChild.getChildren().isEmpty() || isMatch(filteredChild.getValue(), filter)) {
filteredRoot.getChildren().add(filteredChild);
}
}
}
/**
* Comparator for tree filter
* @param value
* @param filter
* @return
*/
private boolean isMatch(FilePath value, String filter) {
return value.toString().toLowerCase().contains( filter.toLowerCase()); // TODO: optimize or change (check file extension, etc)
}
/**
* Show original tree or filtered tree depending on filter
* @param filter
*/
private void filterChanged(String filter) {
if (filter.isEmpty()) {
treeView.setRoot(rootTreeItem);
}
else {
TreeItem<FilePath> filteredRoot = createTreeRoot();
filter(rootTreeItem, filter, filteredRoot);
treeView.setRoot(filteredRoot);
}
}
/**
* Create root node. Used for the original tree and the filtered tree.
* Another option would be to clone the root.
* @return
*/
private TreeItem<FilePath> createTreeRoot() {
TreeItem<FilePath> root = new TreeItem<FilePath>( new FilePath( Paths.get( ROOT_FOLDER)));
root.setExpanded(true);
return root;
}
/**
* Wrapper for the path with overwritte toString method. We only want to see the last path part as tree node, not the entire path.
*/
private static class FilePath {
Path path;
String text;
public FilePath( Path path) {
this.path = path;
// display text: the last path part
// consider root, e. g. c:\
if( path.getNameCount() == 0) {
this.text = path.toString();
}
// consider folder structure
else {
this.text = path.getName( path.getNameCount() - 1).toString();
}
}
public Path getPath() {
return path;
}
public String toString() {
// hint: if you'd like to see the entire path, use this:
// return path.toString();
// show only last path part
return text;
}
}
public static void main(String[] args) {
launch(args);
}
}
只需在文本字段中输入搜索文本,即可相应地过滤树。
如果您想查看完整路径,可以更改toString()方法。此外,当前搜索子字符串而不是文件扩展名。这只是为了演示,根据您的需求进行调整是微不足道的。
如果您想在另一个树视图或列表视图中显示树的某些部分,则会应用类似的机制。
示例,如果您希望获得包含带有e的文件的所有节点的树结构。 G。文本过滤器中的子串“mp3”,而不是在树中显示文件本身,这里是过滤方法的修改版本:
/**
* Create new filtered tree structure
* @param root
* @param filter
* @param filteredRoot
*/
private void filter(TreeItem<FilePath> root, String filter, TreeItem<FilePath> filteredRoot) {
for (TreeItem<FilePath> child : root.getChildren()) {
TreeItem<FilePath> filteredChild = new TreeItem<>( child.getValue());
filteredChild.setExpanded(true);
filter(child, filter, filteredChild );
boolean hasItem = false;
for (TreeItem<FilePath> subChild: child.getChildren()) {
if( isMatch( subChild.getValue(), filter)) {
hasItem = true;
break;
}
}
if (!filteredChild.getChildren().isEmpty() || hasItem) {
filteredRoot.getChildren().add(filteredChild);
}
}
}
如果你想以执行/内存效率的方式执行此操作,可以查看TreeItem示例代码,该代码仅在您导航到文件夹时扫描文件夹。