配置扫描本地系统的TreeView仅包含文件类型为

时间:2015-12-30 18:06:27

标签: java file javafx treeview observablelist

好的,所以我使用了本网站的第二块代码 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();
            }
        };
    }
}

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

1 个答案:

答案 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示例代码,该代码仅在您导航到文件夹时扫描文件夹。