Reputation: 339
Any ideas on how to represent nested paths within as TreeItems?
This is my input as several Strings (besides: I don't know the strings before so the whole thing should be as generic as possible):
input1
input2.sub1
input2.sub2
input2.sub2.subsub1
input2.sub3
input3
input3.sub1
input3.sub1.subsub1
input3.sub1.subsub1.subsubsub1
input3.sub2
Since I'm on the way at the moment, I cannot post any source code unfortunately. But before asking, I tried several approaches such as transferring the paths directly to the TreeView (seems complicated) or having some sort of tree representation in java first (mostly everything with recursive methods).
The attached screenshots shows what I try to achieve in a generic way.
Thanks a lot in advance — best wishes from Germany :)
Upvotes: 0
Views: 944
Reputation: 82491
Store the items "path" in a map so that you can look them up, create nodes that do not exist and use existing nodes. The easiest way to do this would be a recursive method:
private static TreeItem<String> getItem(Map<String, TreeItem<String>> items, TreeItem<String> root, String itemPath) {
TreeItem<String> result = items.get(itemPath);
if (result == null) {
// new item needs to be created
int index = itemPath.lastIndexOf('.');
result = new TreeItem<>(itemPath.substring(index + 1));
items.put(itemPath, result);
if (index == -1) {
// no more subpaths => connect to root
root.getChildren().add(result);
} else {
// find/create parent
TreeItem<String> parent = getItem(items, root, itemPath.substring(0, index));
parent.getChildren().add(result);
}
}
return result;
}
@Override
public void start(Stage primaryStage) throws Exception {
List<String> paths = Arrays.asList(
"input1",
"input2.sub1",
"input2.sub2",
"input2.sub2.subsub1",
"input2.sub3",
"input3",
"input3.sub1",
"input3.sub1.subsub1",
"input3.sub1.subsub1.subsubsub1",
"input3.sub2");
TreeItem<String> root = new TreeItem<>();
Map<String, TreeItem<String>> items = new HashMap<>();
for (String path : paths) {
getItem(items, root, path);
}
TreeView<String> treeView = new TreeView<>(root);
treeView.setShowRoot(false);
Scene scene = new Scene(treeView);
primaryStage.setScene(scene);
primaryStage.show();
}
Upvotes: 1
Reputation: 209694
You can iterate through your list of strings, split each one by the delimiter (.
), and then search through the tree, adding items as needed. Something like:
List<String> paths = ... ;
TreeItem<String> root = new TreeItem<>("root");
for (String path : paths) {
TreeItem<String> current = root ;
for (String component : path.split("\\.")) {
current = getOrCreateChild(current, component);
}
}
// ...
private TreeItem<String> getOrCreateChild(TreeItem<String> parent, String value) {
for (TreeItem<String> child : parent.getChildren()) {
if (value.equals(child.getValue())) {
return child ;
}
}
TreeItem<String> newChild = new TreeItem<>(value);
parent.getChildren().add(newChild);
return newChild ;
}
Note there's nothing particularly special about strings here, you could do this with any type. Here's a SSCCE which uses a generic version of the method:
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.stage.Stage;
public class TreeFromPaths extends Application {
private final List<String> paths = Arrays.asList(
"input1",
"input2.sub1",
"input2.sub2",
"input2.sub2.subsub1",
"input2.sub3",
"input3",
"input3.sub1",
"input3.sub1.subsub1",
"input3.sub1.subsub1.subsubsub1",
"input3.sub2"
);
private <S,T> TreeView<T> createTree(
List<S> paths,
Function<S, ? extends Iterable<T>> pathSplitter,
T rootValue) {
TreeItem<T> root = new TreeItem<>(rootValue);
populateTree(paths, pathSplitter, root);
TreeView<T> tree = new TreeView<>(root);
tree.setShowRoot(false);
return tree;
}
private <S,T> void populateTree(
List<S> paths,
Function<S, ? extends Iterable<T>> pathSplitter,
TreeItem<T> root) {
for (S path : paths) {
TreeItem<T> current = root ;
for (T component : pathSplitter.apply(path)) {
current = getOrCreateChild(current, component);
}
}
}
private <T> TreeItem<T> getOrCreateChild(TreeItem<T> parent, T value) {
for (TreeItem<T> child : parent.getChildren()) {
if (value.equals(child.getValue())) {
return child ;
}
}
TreeItem<T> newChild = new TreeItem<>(value);
parent.getChildren().add(newChild);
return newChild ;
}
@Override
public void start(Stage primaryStage) {
Function<String, List<String>> pathSplitter =
path -> Arrays.asList(path.split("\\."));
TreeView<String> treeView = createTree(paths, pathSplitter, "root");
primaryStage.setScene(new Scene(treeView, 400, 400));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Upvotes: 1