実現したいこと と 試したこと
JavaFxのTreeViewにフォルダ ファイル(ディレクトリ)階層を表示したいです。
Oracleの公式サイト(ドキュメント)にメモリーを消費しない効率的な方法が紹介されていたので、テスト①のように作りました。
「フォルダを展開した時にその子フォルダのみを設定している」ということが標準出力で調べて分かりました(詳しいことは不明)(効率的ですね)。
しかし、要素全てがフルパスで表示されてしまって見ずらい(画像添付)ので改良したいと思いました。
そこでjava.io.Fileを自作クラスFileExに置き換えて、テスト②のように改良してみました。
しかし、ルートフォルダが空文字になってしまったり、ファイルが表示されないので困っています。
教えて頂きたいこと
以下について、できるだけ教えて頂きたいです。(全てではなくても有難いです。)
・TreeItem と TreeCell の違いや役割について。
・テスト②について、無駄な部分や間違い、他のアプローチについて
・選択されたフォルダやファイルのフルパスを取得する方法(クリックイベントなどで)
宜しくお願い致します。
目指すところ
(理想なので分かることだけでも有難いです。)
・test.TestBrowser1.javaファイルのように再帰処理を使うなど、ソースコードが少なくて済むこと。
・大量のフォルダ ファイル があっても重くならないこと。
参考にしたサイト
https://qiita.com/sipadan2003/items/71ddbf0259ce89ba5243
https://qiita.com/sipadan2003/items/4b909a294b039b0bfd2f
https://qiita.com/sipadan2003/items/9305e6c1f52e8e0621d7
https://qiita.com/sipadan2003/items/d9afee2d6eb039f2b832
https://aoe-tk.hatenablog.com/entry/20131206/1386345344
https://docs.oracle.com/javase/jp/8/javafx/api/
https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/control/TreeItem.html
テスト①
以下のソースコードを参考にしました。
https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/control/TreeItem.html
AppTopWindowController.javaファイル
java
1import java.net.URL; 2import java.util.ResourceBundle; 3 4import javafx.fxml.FXML; 5import javafx.scene.control.TreeView; 6import java.io.File; 7import test.TestBrowser1; 8 9public class AppTopWindowController { 10 @FXML private ResourceBundle resources; 11 @FXML private URL location; 12 @FXML private TreeView<File> folderTree; 13 14 @FXML 15 void initialize() { 16 TestBrowser1 testBrowser1 = new TestBrowser1(); 17 folderTree.setRoot(testBrowser1.buildFileSystemBrowser()); 18 } 19}
test.TestBrowser1.javaファイル
java
1package test; 2 3import java.io.File; 4 5import javafx.collections.FXCollections; 6import javafx.collections.ObservableList; 7import javafx.scene.control.TreeItem; 8 9//https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/control/TreeItem.html を参考にしたもの。 10 11public class TestBrowser1 { 12 public TreeItem<File> buildFileSystemBrowser() { 13 TreeItem<File> root = createNode(new File("D:\"));//使用環境はwindowsなのでD:\となる。開発環境ではエスケープしてD:\とする。 14 return root; 15 } 16 17 // This method creates a TreeItem to represent the given File. It does this 18 // by overriding the TreeItem.getChildren() and TreeItem.isLeaf() methods 19 // anonymously, but this could be better abstracted by creating a 20 // 'FileTreeItem' subclass of TreeItem. However, this is left as an exercise 21 // for the reader. 22 private TreeItem<File> createNode(final File f) { 23 return new TreeItem<File>(f) { 24 // We cache whether the File is a leaf or not. A File is a leaf if 25 // it is not a directory and does not have any files contained within 26 // it. We cache this as isLeaf() is called often, and doing the 27 // actual check on File is expensive. 28 private boolean isLeaf; 29 30 // We do the children and leaf testing only once, and then set these 31 // booleans to false so that we do not check again during this 32 // run. A more complete implementation may need to handle more 33 // dynamic file system situations (such as where a folder has files 34 // added after the TreeView is shown). Again, this is left as an 35 // exercise for the reader. 36 private boolean isFirstTimeChildren = true; 37 private boolean isFirstTimeLeaf = true; 38 39 @Override public ObservableList<TreeItem<File>> getChildren() { 40 if (isFirstTimeChildren) { 41 isFirstTimeChildren = false; 42 43 // First getChildren() call, so we actually go off and 44 // determine the children of the File contained in this TreeItem. 45 super.getChildren().setAll(buildChildren(this)); 46 } 47 return super.getChildren(); 48 } 49 50 @Override public boolean isLeaf() { 51 if (isFirstTimeLeaf) { 52 isFirstTimeLeaf = false; 53 File f = (File) getValue(); 54 isLeaf = f.isFile(); 55 } 56 return isLeaf; 57 } 58 59 private ObservableList<TreeItem<File>> buildChildren(TreeItem<File> TreeItem) { 60 File f = TreeItem.getValue(); 61 if (f != null && f.isDirectory()) { 62 File[] files = f.listFiles(); 63 if (files != null) { 64 ObservableList<TreeItem<File>> children = FXCollections.observableArrayList(); 65 66 for (File childFile : files) { 67 if (childFile.isDirectory()){ 68 System.out.println(childFile.getName()); 69 children.add(createNode(childFile)); 70 } 71 } 72 73 return children; 74 } 75 } 76 return FXCollections.emptyObservableList(); 77 } 78 }; 79 } 80}
テスト②
AppTopWindowController.javaファイル (FXMLのコントローラー クラス)
java
1import java.net.URL; 2import java.util.ResourceBundle; 3 4import javafx.fxml.FXML; 5import javafx.scene.control.TreeView; 6import test.FileEx; //java.io.Fileとjava.io.File.getName()を保持するモデル。 7import test.TestBrowser2; 8 9public class AppTopWindowController { 10 @FXML private ResourceBundle resources; 11 @FXML private URL location; 12 @FXML private TreeView<FileEx> folderTree; 13 14 @FXML 15 void initialize() { 16 TestBrowser2 testBrowser2 = new TestBrowser2(); 17 TestBrowser2.buildFileSystemBrowser(folderTree); 18 } 19}
test.FileEx.javaファイル(java.io.Fileとjava.io.File.getName()を保持するモデル。)
java
1package test; 2 3import java.io.File; 4 5public class FileEx {//java.io.Fileとjava.io.File.getName()を保持するモデル。 6 private String name; 7 private File f; 8 9 FileEx(String name,File f){//コンストラクタ 10 this.name=name; 11 this.f=f; 12 } 13 14 String getName(){ 15 return this.name; 16 } 17 File getFile(){ 18 return this.f; 19 } 20}
test.FileTreeCell.javaファイル
java
1package test; 2 3import javafx.scene.control.TreeCell; 4 5public class FileTreeCell extends TreeCell<FileEx> { 6 //コンストラクタ 7 public FileTreeCell() { 8 //setText(""); 9 } 10 11 @Override 12 protected void updateItem(FileEx fileEx, boolean empty) { 13 super.updateItem(fileEx, empty); 14 if (empty) { 15 16 } else { 17 setText(fileEx.getName()); 18 } 19 } 20}
test.TestBrowser2.javaファイル
java
1package test; 2 3import java.io.File; 4 5import javafx.collections.FXCollections; 6import javafx.collections.ObservableList; 7import javafx.scene.control.TreeCell; 8import javafx.scene.control.TreeItem; 9import javafx.scene.control.TreeView; 10import javafx.util.Callback; 11 12//https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/control/TreeItem.html を参考に改良。 13 14public class TestBrowser2{ 15 public void buildFileSystemBrowser(TreeView<FileEx> treeView) { 16 File rootFile =new File("D:\"); //使用環境はwindowsなのでD:\となる。開発環境ではエスケープしてD:\とする。 17 TreeItem<FileEx> root = createNode(new FileEx(rootFile.getName(),rootFile)); 18 19 treeView.setCellFactory(new Callback<TreeView<FileEx>, TreeCell<FileEx>>() { 20 @Override 21 public TreeCell<FileEx> call(TreeView<FileEx> treeView) { 22 return new FileTreeCell(); 23 } 24 }); 25 treeView.setRoot(root); 26 } 27 28 private TreeItem<FileEx> createNode(final FileEx f) { 29 return new TreeItem<FileEx>(f) { 30 private boolean isLeaf; 31 private boolean isFirstTimeChildren = true; 32 private boolean isFirstTimeLeaf = true; 33 34 @Override 35 public ObservableList<TreeItem<FileEx>> getChildren() { 36 if (isFirstTimeChildren) { 37 isFirstTimeChildren = false; 38 super.getChildren().setAll(buildChildren(this)); 39 } 40 return super.getChildren(); 41 } 42 43 @Override public boolean isLeaf() { 44 if (isFirstTimeLeaf) { 45 isFirstTimeLeaf = false; 46 File f = getValue().getFile(); 47 isLeaf = f.isFile(); 48 } 49 return isLeaf; 50 } 51 52 private ObservableList<TreeItem<FileEx>> buildChildren(TreeItem<FileEx> TreeItem) { 53 File f = TreeItem.getValue().getFile(); 54 if (f != null && f.isDirectory()) { 55 File[] files = f.listFiles(); 56 if (files != null) { 57 ObservableList<TreeItem<FileEx>> children = FXCollections.observableArrayList(); 58 for (File childFile : files) { 59 if (childFile.isDirectory()){ 60 System.out.println(childFile.getName()); 61 FileEx tempFileEx = new FileEx(childFile.getName(),childFile); 62 children.add(createNode(tempFileEx)); 63 } 64 } 65 return children; 66 } 67 } 68 return FXCollections.emptyObservableList(); 69 } 70 }; 71 } 72}
バージョン
Java 8
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。