简体   繁体   English

Linux中的Java TreeView问题

[英]Java TreeView issue in linux

I'm trying to create a file manager inside an app I am developing. 我正在尝试在正在开发的应用程序中创建文件管理器。 This file manager uses TreeView and TreeItem, but I am stuck on getting the root folder. 该文件管理器使用TreeView和TreeItem,但是我一直在获取根文件夹。 I hope this image let me explain better . 我希望这张图片能让我更好地解释 This is the main class: 这是主要的类:

public class JavaFXFileBrowseDemoApp extends Application {
private TreeView<String> treeView;

public static void main(String[] args){
    launch(args);
}

@Override
public void start(Stage primaryStage){

    //create tree pane
    VBox treeBox=new VBox();
    treeBox.setPadding(new Insets(10,10,10,10));
    treeBox.setSpacing(10);
    //setup the file browser root
    String hostName="computer";

    try{
        hostName=InetAddress.getLocalHost().getHostName();
    }
    catch(UnknownHostException x){}

    TreeItem<String> rootNode = new TreeItem<>(hostName, new ImageView(FilePathTreeItem.computer)); // FilePathTreeItem.computer is just an image

    Iterable<Path> rootDirectories = FileSystems.getDefault().getRootDirectories();

    for(Path name : rootDirectories){
        System.out.println(name.getFileName()); // <----- it gives me null
        FilePathTreeItem treeNode=new FilePathTreeItem(name);
        rootNode.getChildren().add(treeNode);
    }


    rootNode.setExpanded(true);
    //create the tree view
    treeView=new TreeView<>(rootNode);
    //add everything to the tree pane
    treeBox.getChildren().addAll(new Label("File browser"),treeView);
    VBox.setVgrow(treeView,Priority.ALWAYS);

    //setup and show the window
    primaryStage.setTitle("JavaFX File Browse Demo");
    StackPane root=new StackPane();
    root.getChildren().addAll(treeBox);
    primaryStage.setScene(new Scene(root,400,300));
    primaryStage.show();
}

} }

Here there is the FilePathTreeItem class: 这里是FilePathTreeItem类:

public class FilePathTreeItem extends TreeItem<String>{
public static Image computer = new Image(ClassLoader.getSystemResourceAsStream("computer.png"));
public static Image folderClosed = new Image(ClassLoader.getSystemResourceAsStream("folder-closed.png"));
public static Image folderOpened = new Image(ClassLoader.getSystemResourceAsStream("folder-opened.png"));
public static Image genericText= new Image(ClassLoader.getSystemResourceAsStream("generic-text.png"));

private String fullPath;
private boolean isDirectory;

public FilePathTreeItem(Path file){
    super(file.toString());
    fullPath = file.toString();

    // test if this is a directory and set the icon
    if (Files.isDirectory(file)){
        isDirectory = true;
        setGraphic(new ImageView(folderClosed));
    }
    else{
        isDirectory = false;

        if (file.endsWith("txt")){
            setGraphic(new ImageView(genericText));
        }
    }

    if(!fullPath.endsWith(File.separator)){
        String value = file.toString();
        int indexOf = value.lastIndexOf(File.separator);

        if (indexOf > 0){
            setValue(value.substring(indexOf + 1));
        }
        else{
            setValue(value);
        }
    }

    this.addEventHandler(TreeItem.<Object>branchExpandedEvent(), new EventHandler(){
        @Override
        public void handle(Event e){
            FilePathTreeItem source = (FilePathTreeItem)e.getSource();
            if (source.isDirectory() && source.isExpanded()){
                ImageView iv = (ImageView)source.getGraphic();
                iv.setImage(folderOpened);
            }

            try{
                if (source.getChildren().isEmpty()){
                    Path path = Paths.get(source.getFullPath());
                    BasicFileAttributes attribs = Files.readAttributes(path, BasicFileAttributes.class);
                    if (attribs.isDirectory()){
                        DirectoryStream<Path> dir = Files.newDirectoryStream(path);

                        for(Path file : dir){
                            FilePathTreeItem treeNode = new FilePathTreeItem(file);
                            source.getChildren().add(treeNode);
                        }
                    }
                }
                else{
                    //if you want to implement rescanning a directory for changes this would be the place to do it
                }
            }
            catch(IOException x){
                x.printStackTrace();
            }
        }
    });

    this.addEventHandler(TreeItem.<Object>branchCollapsedEvent(), new EventHandler(){
        @Override
        public void handle(Event e){
            FilePathTreeItem source = (FilePathTreeItem) e.getSource();
            if (source.isDirectory() && !source.isExpanded()){
                ImageView iv = (ImageView) source.getGraphic();
                iv.setImage(folderOpened);
            }
        }
    });
}

public String getFullPath() {
    return fullPath;
}

public boolean isDirectory() {
    return isDirectory;
}

} }

Your code (and indeed the example you based it on) do not work because no child nodes are added to the tree item until it is expanded. 您的代码(实际上是您基于它的示例)不起作用,因为在展开之前,不会将任何子节点添加到树项。 However, a JavaFX TreeItem cannot be expanded if it is a leaf node, and the definition of leaf node is one that has no child nodes. 但是,如果JavaFX TreeItem是叶节点,则无法展开,并且叶节点的定义是没有子节点的节点。 So you never get a chance to expand the node, and it never gets populated. 因此,您永远都没有机会扩展节点,也永远不会填充节点。

You need to do something along the lines of: 您需要执行以下操作:

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Collectors;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

public class FilePathTreeItem extends TreeItem<String>{
    public static Image computer = new Image(ClassLoader.getSystemResourceAsStream("computer.png"));
    public static Image folderClosed = new Image(ClassLoader.getSystemResourceAsStream("folder.png"));
    public static Image folderOpened = new Image(ClassLoader.getSystemResourceAsStream("folder-open.png"));
    public static Image genericText= new Image(ClassLoader.getSystemResourceAsStream("text-x-generic.png"));

    private ImageView imageView = new ImageView();

    private String fullPath;
    private boolean isDirectory;

    private boolean isFirstTimeLeaf = true ;
    private boolean isFirstTimeChildren = true ;
    private boolean isLeaf ;    

    public FilePathTreeItem(Path file){
        super(file.toString());
        fullPath = file.toString();

        // test if this is a directory and set the icon
        if (Files.isDirectory(file)){
            isDirectory = true;
            setGraphic(new ImageView(folderClosed));
        }
        else{
            isDirectory = false;

            if (file.endsWith("txt")){
                setGraphic(new ImageView(genericText));
            }
        }

        if(!fullPath.endsWith(File.separator)){
            String value = file.toString();
            int indexOf = value.lastIndexOf(File.separator);

            if (indexOf > 0){
                setValue(value.substring(indexOf + 1));
            }
            else{
                setValue(value);
            }
        }

        this.expandedProperty().addListener((obs, wasExpanded, isNowExpanded) -> {
            if (Files.isDirectory(Paths.get(fullPath))) {
                if (isNowExpanded) {
                    imageView.setImage(folderOpened);
                } else {
                    imageView.setImage(folderClosed);
                }
                setGraphic(imageView);
            }
        });


    }

    @Override
    public ObservableList<TreeItem<String>> getChildren() {
        if (isFirstTimeChildren) {
            isFirstTimeChildren = false ;
            super.getChildren().setAll(buildChildren());
        }
        return super.getChildren() ;
    }

    @Override
    public boolean isLeaf() {
        if (isFirstTimeLeaf) {
            isFirstTimeLeaf = false ;
            Path path = Paths.get(fullPath);
            isLeaf = ! Files.isDirectory(path);
        }
        return isLeaf ;
    }

    private ObservableList<TreeItem<String>> buildChildren() {
        Path path = Paths.get(fullPath);
        if (Files.isDirectory(path)) {
            try {
                return Files.list(path).map(FilePathTreeItem::new)
                        .collect(Collectors.toCollection(FXCollections::observableArrayList));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return FXCollections.observableArrayList();
    }

    public String getFullPath() {
        return fullPath;
    }

    public boolean isDirectory() {
        return isDirectory;
    }
}

I kept this fairly close to the example you borrowed from, though I don't particularly like much of his approach. 尽管我不太喜欢他的方法,但我还是很接近您所借鉴的示例。 I did clean up a lot of the event handling and brought some of it up to date (using lambdas etc). 我确实清理了很多事件处理,并更新了一些事件(使用lambda等)。 But really there is still way too much conversion between String s and Path s here: if you'RE building a Tree where each node essentially represents a Path , then you should use a TreeView<Path> and TreeItem<Path> etc, not continually convert everything between strings and paths. 但实际上,这里的StringPath之间仍然有太多转换:如果要构建一个树,其中每个节点本质上代表一个Path ,则应使用TreeView<Path>TreeItem<Path>等,而不是连续使用在字符串和路径之间转换所有内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM