我正在尝试在我正在开发的应用内创建文件管理器。这个文件管理器使用TreeView和TreeItem,但我仍然坚持获取根文件夹。 I hope this image let me explain better。 这是主要的课程:
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();
}
}
这里有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;
}
}
答案 0 :(得分:0)
您的代码(实际上是您基于它的示例)不起作用,因为在扩展之前,没有子节点添加到树项目中。但是,如果JavaFX TreeItem
是叶节点,则无法展开它,并且叶节点的定义是没有子节点的定义。所以你永远不会有机会扩展节点,它永远不会被填充。
你需要做一些事情:
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;
}
}
我保持这与你借来的例子相当接近,尽管我并不特别喜欢他的方法。我确实清理了很多事件处理并使其中的一些更新(使用lambdas等)。但实际上String
和Path
之间仍有太多转换:如果您要构建一个树,其中每个节点基本上代表Path
,那么您应该使用{ {1}}和TreeView<Path>
等,不会在字符串和路径之间不断转换所有内容。