有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java配置一个TreeView,它扫描本地文件系统,只包括具有文件类型的文件夹

好的,我使用了这个网站的第二段代码 http://www.java2s.com/Tutorials/Java/JavaFX/0660__JavaFX_Tree_View.htm其中声明“以下代码从本地文件系统创建动态树”

我不明白该代码是如何根据我的需要进行定制的。特别是覆盖方法,似乎没有一个地方可以添加“仅将文件夹添加到包含mp3文件的子目录”。我认为这可能需要一些更复杂的东西,比如一些能够浏览和删除文件夹的东西。我真的不确定

我曾尝试在我的程序中使用此代码来显示mp3文件。其想法是让两个TreeView并排显示,左侧显示文件夹的层次结构,其中包含mp3文件的文件夹(不显示其他没有mp3文件的文件夹),右侧显示这些文件夹中仅包含mp3文件类型的文件。下面有一个屏幕截图

这是我到目前为止所用的代码,它在VBox中返回一个树视图。 有两段代码被注释掉了。第一个原因是java: search file according to its name in directory and subdirectories不希望搜索我的C:drive。(我不知道为什么)。所以我把它改为只扫描我的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();
            }
        };
    }
}

A preview of a portion of the GUI, the TreeView on the left is from the class shown above


共 (1) 个答案

  1. # 1 楼答案

    您可以递归地创建树结构。有多种机制(请注意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()方法。此外,当前搜索的是子字符串而不是文件扩展名。这只是为了演示,根据您的需要调整它是微不足道的

    如果您希望在另一个树状视图或列表视图中显示树的某些部分,则类似的机制也适用

    示例:如果您希望获得一个树结构,其中所有节点都包含文本筛选器中带有子字符串“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示例代码,该代码仅在您导航到某个文件夹时才会扫描该文件夹