基本上,我正在循环 JarEntry
来自 JarFile
的类(class)并尝试将每个包添加为 TreeView<String>
上的节点.
令人烦恼的是,退回的包裹被斜杠分开。含义:我必须将每个包名称拆分为一个数组,然后检查每个部分(包)是否已存在于树中。
这是我正在使用的示例:
org/something/commons
org/something/commons/more
我需要以某种方式处理每个字符串来创建这种结构:
- 根
- 组织
- 某事
- 公共(public)资源
- 更多
- 某事
- 组织
之后,我需要将非目录条目中的每个类文件添加到每个预先存在的目录节点。
老实说,这是我尝试过实现的最令人困惑的事情。除了创建某种形式的扩展树项类来充当条目包装器或类似的东西之外,我只是想不出一个好的算法来执行此操作。
任何指导将不胜感激。我当前的代码如下:
private void populateTree(Enumeration<String> jarEntries) {
jarFile.stream().forEach(entry -> {
String entryName = entry.getName();
if (entry.isDirectory()) {
String[] packages = entryName.split("/");
for(String packageName : packages) {
// check if already exists in root node
if(root.getChildren().contains(root.getChildren().indexOf(packageName))) {
TreeItem<String> packageNode = root.getChildren().get(root.getChildren().indexOf(packageName));
packageNode.getChildren().add(new TreeItem<String>(packageName));
} else {
root.getChildren().add(new TreeItem<String>(packageName));
}
}
} else {
// it's a file
String fileName = entryName.substring(entryName.lastIndexOf("/"), entryName.length());
String[] packages = entryName.substring(0, entryName.lastIndexOf("/")).split("/");
// somehow loop through each child of the root node and eventually, using some form of traversal algo, get to the package node to add new item to
}
});
root.setExpanded(true);
}
最佳答案
我会创建一个TreeView<JarEntry>
,因此数据由 TreeItem
包裹是 JarEntry
对象。然后使用 cellFactory
指示单元格仅显示路径的最后一部分。
实际上填充树有点棘手,因为 jar 文件不需要包含其目录条目。因此,您最终可能必须在构建结构时创建新条目。我不确定我是否遵循您发布的方法:您不是将所有包及其子包直接添加到根目录(而不是子包到包)吗?
这是 SSCCE。您也许能够找到填充树的更清晰的实现...
import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Stage;
public class JarFileTreeView extends Application {
@Override
public void start(Stage primaryStage) {
TreeView<JarEntry> tree = new TreeView<>();
tree.setShowRoot(false);
TreeItem<JarEntry> root = new TreeItem<>();
tree.setRoot(root);
// only display last portion of the path in the cells:
tree.setCellFactory(tv -> new TreeCell<JarEntry>() {
@Override
public void updateItem(JarEntry item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
String[] pathElements = item.getName().split("/");
setText(pathElements[pathElements.length - 1]);
}
}
});
ObjectProperty<JarFile> jarFile = new SimpleObjectProperty<>();
jarFile.addListener((obs, oldFile, newFile) -> {
if (newFile == null) {
root.getChildren().clear();
} else {
populateTree(root, newFile);
}
});
FileChooser chooser = new FileChooser();
chooser.getExtensionFilters().add(new ExtensionFilter("Jar Files", "*.jar"));
Button loadButton = new Button("Load...");
loadButton.setOnAction(e -> {
File file = chooser.showOpenDialog(primaryStage);
if (file != null) {
try {
jarFile.set(new JarFile(file));
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
BorderPane uiRoot = new BorderPane(tree, null, null, loadButton, null);
BorderPane.setMargin(loadButton, new Insets(10));
BorderPane.setAlignment(loadButton, Pos.CENTER);
Scene scene = new Scene(uiRoot, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private void populateTree(TreeItem<JarEntry> root, JarFile file) {
root.getChildren().clear();
List<JarEntry> entries = file.stream().collect(Collectors.toList());
// sort by length of path (i.e. number of components separated by "/"), then by name:
entries.sort(Comparator
.comparing((JarEntry entry) -> entry.getName().split("/").length)
.thenComparing(entry -> {
String[] pathElements = entry.getName().split("/");
return pathElements[pathElements.length - 1];
}));
for (JarEntry entry : entries) {
// need to find correct parent for entry. That parent (or any of the ancestors)
// might not exist yet, so we create it if necessary as we search.
// Split name up into folder, subfolder, etc:
List<String> pathElements = Arrays.asList(entry.getName().split("/"));
// Search for parent. Start at root:
TreeItem<JarEntry> parent = root;
// Iterate through all elements except the last, traversing tree:
for (int i = 0; i < pathElements.size() - 1 ; i++) {
// name of ancestor entry:
String matchingName = String.join("/", pathElements.subList(0, i+1));
final TreeItem<JarEntry> current = parent ;
// update parent with current parent's descendant, matching appropriate name:
parent = current.getChildren().stream()
.filter(child -> child.getValue().getName().equals(matchingName))
.findFirst()
// it's possible this ancestor didn't yet exist, so we create it,
// and add it to the correct parent:
.orElseGet(() -> {
JarEntry newEntry = new JarEntry(matchingName);
TreeItem<JarEntry> newItem = new TreeItem<>(newEntry);
current.getChildren().add(newItem);
return newItem ;
});
}
// after all that, we have a valid parent:
parent.getChildren().add(new TreeItem<>(entry));
}
}
public static void main(String[] args) {
launch(args);
}
}
关于java - 如何使用 JarEntries 填充 JavaFX TreeView(包 - 文件),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32170723/