[英]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. 但实际上,这里的
String
和Path
之间仍然有太多转换:如果要构建一个树,其中每个节点本质上代表一个Path
,则应使用TreeView<Path>
和TreeItem<Path>
等,而不是连续使用在字符串和路径之间转换所有内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.