1

It is said in documentation, that

TreeTableView control is designed to visualize an unlimited number of rows of data

Unfortunately, I can't see any means for this in the doc.

All elements are stored in TreeItem<> classes and stored in memory. Although, one can implement "unlimitness" with ObservableList<> I see no way to implement this on nested observable lists.

"Unlimitness" require loading data by-demand, not storing it in memory.

So is it finally possible to display data on demand in TreeTableView?

Dims
  • 47,675
  • 117
  • 331
  • 600
  • Possible duplicate of [JavaFX bad design: Row identity in observable lists behind the TableView?](http://stackoverflow.com/questions/36937118/javafx-bad-design-row-identity-in-observable-lists-behind-the-tableview) – Itai Jun 13 '16 at 11:57
  • The above linked question refers to `TableView`, but it's the same issue. I believe James_D's answer could apply (with the necessary changes) to `TreeTableView` as well. – Itai Jun 13 '16 at 11:59
  • 2
    Please read javadoc of TreeItem. There is entire section about implementing on-demand loading of nodes, giving filesystem browser as example (which might be not infinite, but you certainly want to load only needed things, rather than pulling entire filesystem into memory). – Artur Biesiadowski Jun 13 '16 at 12:00

1 Answers1

1

As pointed out in the comments, the documentation for TreeItem has an example of lazily-populating the child nodes of the tree item.

Here's a very simple complete example of an infinite tree table. In this example, the child nodes are removed when the tree item is collapsed, allowing them to be garbage collected.

import java.math.BigInteger;
import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.stage.Stage;

public class UnlimitedTreeTableView extends Application {


    @Override
    public void start(Stage primaryStage) {
        TreeTableView<Item> treeTable = new TreeTableView<>();
        treeTable.setRoot(createTreeItem(BigInteger.ZERO));

        treeTable.getColumns().add(column("Item", Item::getName));
        treeTable.getColumns().add(column("Value", Item::getValue));

        primaryStage.setScene(new Scene(treeTable));
        primaryStage.show();
    }

    private TreeItem<Item> createTreeItem(BigInteger value) {
        TreeItem<Item> item = new TreeItem<Item>(new Item(String.format("Item %,d", value), value)) {

            private boolean childrenComputed = false ;

            {
                expandedProperty().addListener((obs, wasExpanded, isNowExpanded) -> {
                    if (! isNowExpanded) { // remove child nodes...
                        super.getChildren().clear();
                        childrenComputed = false ;
                    }
                });
            }

            @Override
            public ObservableList<TreeItem<Item>> getChildren() {
                if (! childrenComputed) {
                    Item item = getValue();
                    BigInteger value = item.getValue() ;
                    BigInteger valueTimes10 = value.multiply(BigInteger.TEN);
                    for (int i = 0 ; i < 10 ; i++) {
                        BigInteger v = BigInteger.valueOf(i);
                        super.getChildren().add(createTreeItem(valueTimes10.add(v)));
                    }
                    childrenComputed = true ;
                }
                return super.getChildren();
            }

            @Override
            public boolean isLeaf() {
                return false ;
            }
        };

        return item ;
    }

    private static <S,T> TreeTableColumn<S,T> column(String title, Function<S,T> property) {
        TreeTableColumn<S,T> column = new TreeTableColumn<>(title);
        column.setCellValueFactory(cellData -> 
            new SimpleObjectProperty<T>(property.apply(cellData.getValue().getValue())));
        column.setPrefWidth(200);
        return column ;
    }

    public static class Item {
        private final BigInteger value ;
        private final String name ;

        public Item(String name, BigInteger value) {
            this.name = name ;
            this.value = value ;
        }

        public BigInteger getValue() {
            return value;
        }

        public String getName() {
            return name;
        }


    }

    public static void main(String[] args) {
        launch(args);
    }
}
James_D
  • 201,275
  • 16
  • 291
  • 322
  • (1) I got stackoverflow at some (unknown) moment (2) your structure is "fractal" i.e. repeated from level to level, but if we have specific structure at any place, we can face with difficulties. It would be better to have addressing system and a data structure, returning item in response to address. As it made in Swing. – Dims Jun 13 '16 at 14:23
  • (1) didn't see that happen but I can play with it some more later. (2) not sure I see the distinction. In my example the child nodes are computed as a function of the "current" TreeItem and its value. The computation here is trivial but it could just as easily talk to a service etc. – James_D Jun 13 '16 at 16:48