AnotherNewbplusplus
AnotherNewbplusplus

Reputation: 215

CheckBoxTreeTableCell Select All Children Under Parent Event

I'm trying to select all child check boxes from a parent root. The action is invoked when the parent check box is selected.

Here's the pseudo/modified/shortened set up with scenebuilder:

@FXML
private TreeTableView<Info> testTable;
@FXML
private TreeTableColumn<Info, Boolean> checkBoxCol;

Model:

public class Info{
    private final BooleanProperty onHold;

    public Info(){
        this.onHold = new SimpleBooleanProperty(false);
    }
    public Boolean getOnHold(){
        return onHold.get();
    }
    public void setOnHold(Boolean onHold) {
        this.onHold.set(onHold);
    }
    public BooleanProperty onHoldProperty(){
        return onHold;
    }
}

Controller:

    checkBoxCol.setCellValueFactory(new TreeItemPropertyValueFactory("onHold"));
    checkBoxCol.setCellFactory(CheckBoxTreeTableCell.forTreeTableColumn(checkBoxCol));

End Result would look like this (when parent nodes are clicked):

enter image description here

I tried onEditCommit/start/cancel, but those seem to only affect the cell and not the checkboxes. I am not exactly sure how to get a listener for only the parent nodes so that it can check all values underneath (if they have children). If it's too difficult to only allow just the parent nodes to have the listener, then all the checkbox can have listeners and I can simply check if there are children with:node.getChildren().size()

Upvotes: 1

Views: 1734

Answers (1)

James_D
James_D

Reputation: 209319

You should be able to manage this entirely in the model.

The TreeTableView consists of a TreeItem<Info> root with a bunch of descendent nodes. Just arrange that whenever you create the tree items, you add a listener to the properties:

private TreeItem<Info> createTreeItem(Info info) {
    TreeItem<Info> item = new TreeItem<>(info);
    info.onHoldProperty().addListener((obs, wasOnHold, isNowOnHold) -> {
        if (isNowOnHold) {
            item.getChildren().forEach(child -> child.getValue().setOnHold(true));
        }
    });
    return item ;
}

Complete example:

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.CheckBoxTreeTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class TreeTableViewInheritableCheckBoxes extends Application {

    @Override
    public void start(Stage primaryStage) {
        TreeTableView<Info> table = new TreeTableView<>();
        table.setEditable(true);

        TreeTableColumn<Info, Boolean> infoCol = new TreeTableColumn<>("Info");
        infoCol.setPrefWidth(200);

        infoCol.setCellValueFactory(cellData -> cellData.getValue().getValue().onHoldProperty());
        infoCol.setCellFactory(CheckBoxTreeTableCell.forTreeTableColumn(infoCol));
        table.getColumns().add(infoCol);

        TreeItem<Info> root = createTreeItem(new Info());

        buildTree(root, 0);

        table.setRoot(root);

        primaryStage.setScene(new Scene(new BorderPane(table), 250, 400));
        primaryStage.show();
    }

    private void buildTree(TreeItem<Info> parent, int depth) {
        if (depth > 2) return ;
        for (int i = 0; i < 5; i++) {
            TreeItem<Info> item = createTreeItem(new Info());
            parent.getChildren().add(item);
            buildTree(item, depth + 1);
        }
    }

    private TreeItem<Info> createTreeItem(Info info) {
        TreeItem<Info> item = new TreeItem<>(info);
        info.onHoldProperty().addListener((obs, wasOnHold, isNowOnHold) -> {
            if (isNowOnHold) {
                item.getChildren().forEach(child -> child.getValue().setOnHold(true));
            }
        });
        return item ;
    }

    public static class Info {
        private final BooleanProperty onHold;

        public Info(){
            this.onHold = new SimpleBooleanProperty(false);
        }
        public Boolean getOnHold(){
            return onHold.get();
        }
        public void setOnHold(Boolean onHold) {
            this.onHold.set(onHold);
        }
        public BooleanProperty onHoldProperty(){
            return onHold;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Upvotes: 2

Related Questions