Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bind a domain object to a JavaFX TreeView?

How can I bind a domain object to a JavaFX TreeView? ComboBox has getItems() and you can add something to that collection. TreeView does not seem to have such a method. I could only build the tree manually by adding TreeItems to the TreeView's root and then using getChildren().add(...) to add children, but there seems no way of just adding an observable tree structure.

The domain object can read itself from a file and write itself to a file. It has methods to modify its contents. How do I best hook this up with a TreeView so that the user can add and delete nodes?

I don't want GUI code (i.e., JavaFX classes) in my domain objects.

Do I need to write an Adapter class that can turn my domain object into a JavaFX tree? Then add listeners to the tree and map the changes back to the domain object? Or is there a better way?

like image 848
Robert Avatar asked Jan 12 '14 23:01

Robert


1 Answers

Some time ago I had a similar problem. I've written a custom TreeItem implementation that can handle recursive data structures. I've written a blog post with a detailed explanation here.

The code for the RecursiveTreeItem can be found as gist.

As an example think of a class Task that can contain many sub-tasks and so on.

public class Task {
    private ObservableList<Task> subtasks = FXCollections.observableArrayList();

    public ObservableList<Task> getSubtasks() {
        return subtasks;
    }
}

In this case you could use it as follows:

Task root = new Task();
TreeItem<Task> rootItem = new RecursiveTreeItem<Task>(root, Task::getSubtasks); 
tree.setRoot(rootItem);

The second parameter is of type Callback<T, ObservableList<T>>: a function that takes an element of T (in our case Task) and returns the child elements for this element. In the example I've used a method reference as a shortcut.

This is a fully reactive implementation i.e. when a new sub item is added it will immediately be shown in the TreeView.

You said you don't like to have JavaFX classes in you domain model. In this case you could write something like this (not tested):

TreeItem<Task> rootItem = new RecursiveTreeItem<Task>(root, 
    task -> FXCollections.observableArrayList(task.getSubtasks()));

Here getSubtasks() returns a plain List<Task> that is wrapped in an observableList. But of cause in this case the TreeView won't update automatically when your model changes.

like image 142
Manuel Mauky Avatar answered Nov 01 '22 02:11

Manuel Mauky