I have three domain objects in my app as follows :
public class Workflow {
private String name;
private List<Sheet> sheets;
}
public class Sheet {
private String name;
private List<Task> tasks;
}
public class Task {
private String name;
}
All three are dependent as Workflow -> Sheet -> Task. My goal is to build TreeView so that it look like below :
-Workflow
|
- workflow name
-Sheets
|
- sheet name
- Tasks
|
- task name
So far, I have build a sample that builds more less what I expect, but it's not generic and 'automated' at all.
public class TreeViewSample extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Tree View Sample");
Workflow w = setup();
TreeItem<String> rootItem = new TreeItem<String> ("Workflow");
rootItem.setExpanded(true);
TreeItem<String> item = new TreeItem<String> (w.getName());
rootItem.getChildren().add(item);
(...)
TreeView<String> tree = new TreeView<String> (rootItem);
StackPane root = new StackPane();
root.getChildren().add(tree);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
private Workflow setup(){
Workflow wflow = new Workflow();
wflow.setName("wflow name");
wflow.setSheets(Arrays.asList(new Sheet("sheet name", Arrays.asList(new Task("task name")))));
return wflow;
}
Can someone advise on how I can recursively go to my domain objects and build the TreeView as in my example ?
You have to create a common Model
to all of you models(Workflow, Sheet,Task), since all have a String property, it is quite simple to create one. Let's suppose we have the following model:
public class Model {
private String name;
public Model(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return getName();
}
}
class Workflow {
private String name;
private List<Sheet> sheets = new ArrayList<>();
public Workflow(String name) {
this.name = name;
}
public String getName() {
return name;
}
public List<Sheet> getSheets() {
return sheets;
}
}
class Sheet {
private String name;
private List<Task> tasks = new ArrayList<>();
public Sheet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public List<Task> getTasks() {
return tasks;
}
}
class Task {
private String name;
public Task(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
I kept there together all of your models, to see them better.
I see you don't use any .fxml
file at your app, mine is with .fxml
I recommend that you separate at least to separate the Main
class from the Controller
class, like:
public class Main extends Application{
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("View.fxml"));
AnchorPane pane = loader.load();
primaryStage.setScene(new Scene(pane,800,600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Then the Controller class:
public class Controller implements Initializable {
@FXML
private TreeView<Model> treeView;
@Override
public void initialize(URL location, ResourceBundle resources) {
Workflow workflow = createWorkflow(); // This just sets up the models that you are using.
// You have to create a root in your case the "Workflow"
TreeItem<Model> root = new TreeItem<>(new Model(workflow.getName()));
// The foreach sheet you create a branch
workflow.getSheets().forEach(sheet -> {
TreeItem<Model> sheetBranch = new TreeItem<>(new Model(sheet.getName()));
// Then you have to add each branch to the root
root.getChildren().add(sheetBranch);
// Then foreach sheet you create a task item
sheet.getTasks().forEach(task -> {
TreeItem<Model> taskItem = new TreeItem<>(new Model(task.getName()));
// Then you have to add each task to its sheet parent
sheetBranch.getChildren().add(taskItem);
});
});
// Finally, you set the root for the TreeView. Of course this can be done right after instantiating the root.
treeView.setRoot(root);
}
// ------------------- Setup the model -----------------------
private Workflow createWorkflow() {
Workflow workflow = new Workflow("Workflow");
workflow.getSheets().addAll(createSheets());
return workflow;
}
private List<Sheet> createSheets() {
List<Sheet> sheets = new ArrayList<>();
IntStream.range(1, 10).forEach(value -> sheets.add(createSheet()));
return sheets;
}
private Sheet createSheet() {
Sheet sheet = new Sheet("Sheet" + new Random().nextInt(100)); // Random added to have different names
sheet.getTasks().addAll(createTasks());
return sheet;
}
private List<Task> createTasks() {
List<Task> tasks = new ArrayList<>();
IntStream.range(1, 5).forEach(value -> tasks.add(createTask()));
return tasks;
}
private Task createTask() {
return new Task("Task" + new Random().nextInt(100)); // Random added to have different names
}
}
Just in case if you need here is the .fxml
file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TreeView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="stackoverflow.tree.Controller">
<TreeView fx:id="treeView"/>
</AnchorPane>
If you don't know the depth of the TreeView
you can create all of the branches or leaves using recursion. In this case it is much simpler to use two foreachs instead of creating a recursive method which builds the tree structure.