Taelsin
Taelsin

Reputation: 1090

How to enable/disable a button based on boolean property within a tablerow

As the title states, I'm trying to enable/disable a button within a table row based upon a boolean within that table row's data. Here's my code so far:

col.setCellFactory(new Callback<TableColumn<ExampleRow, String>, TableCell<ExampleRow, String>>() {
        @Override
        public TableCell call(final TableColumn<ExampleRow, String> param){
            final Button btn = new Button("Save");
            final TableCell<ExampleRow, String> cell = new TableCell<ExampleRow, String>(){

                @Override
                public void updateItem(String item, boolean empty){
                    super.updateItem(item, empty);
                    if(empty){
                        setGraphic(null);
                        setText(null);
                    } else {
                        btn.setPrefWidth(col.getWidth());
                        btn.setPadding(Insets.EMPTY);
                        btn.setOnAction(event -> {

                        });
                        setGraphic(btn);
                        setText(null);
                    }
                }
            };
            ExampleRow row = (ExampleRow)cell.getTableRow().getItem(); //NPE here
            btn.setDisable(!row.hasChanged());
            return cell;
        }
    });

Unfortunately my code breaks on the fifth from the bottom line. If I exclude that line and change the line below to btn.setDisable(true) it works wonderfully. What can I do to disable this button based upon the data in which the button resides?

Upvotes: 1

Views: 2270

Answers (1)

fabian
fabian

Reputation: 82491

You aren't using the item anyways, so you could just make it a Boolean and use the value of the changed property. This allows you to enable/disable the button in the updateItem method:

Example:

public static class Item {
    private final BooleanProperty changed = new SimpleBooleanProperty();

    public final boolean isChanged() {
        return this.changed.get();
    }

    public final void setChanged(boolean value) {
        this.changed.set(value);
    }

    public final BooleanProperty changedProperty() {
        return this.changed;
    }

}

@Override
public void start(Stage primaryStage) {
    TableView<Item> table = new TableView();
    table.getItems().addAll(new Item(), new Item(), new Item());

    TableColumn<Item, Boolean> column = new TableColumn<>();
    column.setCellValueFactory(cd -> cd.getValue().changedProperty());
    column.setCellFactory(col -> new TableCell<Item, Boolean>() {

        final Button btn = new Button("Save");

        {
            btn.setOnAction(evt -> {
                Item item = (Item) getTableRow().getItem();
                item.setChanged(false);
            });
        }

        @Override
        protected void updateItem(Boolean item, boolean empty) {
            super.updateItem(item, empty);

            if (empty || item == null) {
                setGraphic(null);
            } else {
                btn.setDisable(!item);
                setGraphic(btn);
            }
        }

    });

    table.getColumns().add(column);

    Button btn = new Button("change");
    btn.setOnAction((ActionEvent event) -> {
        Item item = table.getSelectionModel().getSelectedItem();
        if (item != null) {
            item.setChanged(true);
        }
    });

    VBox root = new VBox(btn, table);

    Scene scene = new Scene(root);

    primaryStage.setScene(scene);
    primaryStage.show();
}

BTW: TableView uses the cellFactory to create the cells. The item, table and tableRow properties are updated later. Therefore retrieving any of those values in the cellFactory's call method itself makes no sense, since none of those values have been assigned at that time.

Upvotes: 2

Related Questions