0

I'm trying to wrap my head around TreeTableViews and I'm doing a pretty bad job at it.

So I have a background task that gets the data I want to use in the TreeTableView, I don't know how I can populate it, as in to bind the TreeTableView's item's property to the task's valueProperty. I've tried looking around and I can't seem to find a simple enough example to demonstrate what i'm looking for. It could be my poor comprehension skills so I'd appreciate it if I could get an explanation of where to go from here.

Main class:

public class App extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("scene.fxml"));
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }
}

scene.fxml

<StackPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/10.0.2-internal"
           xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sample.Scene">
    <TreeTableView fx:id="tblPerson" prefHeight="200.0" prefWidth="200.0">
      <columns>
          <TreeTableColumn fx:id="colName" prefWidth="75.0" text="Name">
              <cellValueFactory>
                  <TreeItemPropertyValueFactory property="name"/>
              </cellValueFactory>
          </TreeTableColumn>
          <TreeTableColumn fx:id="colLikes" prefWidth="75.0" text="Likes">
              <cellValueFactory>
                  <TreeItemPropertyValueFactory property="like"/>
              </cellValueFactory>
          </TreeTableColumn>
      </columns>
    </TreeTableView>
</StackPane>

Model:

public class Person {
    private String name;
    private String like;

    public Person(String name, String like) {
        this.name = name;
        this.like = like;
    }

    public String getName() {
        return name;
    }

    public String getLike() {
        return like;
    }
}

Background Worker:

public class GetPeopleService extends Service<ObservableList<TreeItem<Person>>> {
    @Override
    protected Task<ObservableList<TreeItem<Person>>> createTask() {
        return new GetPeopleTask();
    }

    private static class GetPeopleTask extends Task<ObservableList<TreeItem<Person>>> {
        @Override
        protected ObservableList<TreeItem<Person>> call() throws Exception {
            ObservableList<TreeItem<Person>> myList = FXCollections.observableArrayList();
            //person name should be root node
            myList.addAll(
                    new TreeItem<>(new Person("Foo", "reading")),
                    new TreeItem<>(new Person("Foo", "writing")),
                    new TreeItem<>(new Person("Bar", "cycling")),
                    new TreeItem<>(new Person("Bar", "swimming")),
                    new TreeItem<>(new Person("Alice", "reading"))
            );
            return myList;
        }
    }
}

Controller class

public class Scene implements Initializable {
    @FXML
    private TreeTableView<Person> tblPerson;

    GetPeopleService service = new GetPeopleService();

    @Override
    public void initialize(URL location, ResourceBundle resources) {
      //tblPerson.itemsProperty().bind(....)
      service.start();
    }
}

I would like to make something so that Person's name property is the root node which can be expanded to view their likes. So essentially from the example above, we'd have 3 top level nodes, Foo, Bar and Alice. All their likes are shown on expansion.

Thank you

phsu1
  • 29
  • 5
  • 3
    Think of a `TreeTableView` as a tree with columns. That is to say, it's a tree first and a table second. You're expecting there to be an `items` property but there's not; a `TreeTableView` has a `root` property that holds a single `TreeItem`. Based on your description an at least partial solution is to have a root `TreeItem` and bind its children to the value of the service. Then you can do `tbv.setShowRoot(false)`. – Slaw Jul 05 '21 at 02:30
  • Okay, I think that's where I was getting lost. So for my instance, I can do something like `new TreeItem(new Person("Name","..."))` then set that as root, which I will then hide. then I bind this tree item object's children to the value of the service. Something like that? – phsu1 Jul 05 '21 at 10:55
  • Yes, you can do that. Though since you're hiding the root there's no reason for it to have a value (i.e. it's okay if `root.getValue() == null`). – Slaw Jul 05 '21 at 11:13
  • Awesome. That's all set, thanks. Just one more question though, from my table now, I have 5 top level rows, ("Foo" appears twice, "Bar" twice, "Alice" once). How should I go about marking the `name` as a top level node, so it appears once, then on expansion, you get the list of all say, Foo's `like`s. That's what I'm trying to achieve ultimately – phsu1 Jul 05 '21 at 11:29
  • I figured it out. Thanks for your help @Slaw – phsu1 Jul 05 '21 at 11:56

0 Answers0