Reputation: 95
I want to bind the disable
of a button with dynamically created checkboxes. The Button
should be enabled if a checkbox is selected.
This is my code
public class DietTabPageController {
@FXML
private FlowPane parent;
@FXML
private Button okButton;
private ObservableList<CheckBox> checkBoxes=FXCollections.observableArrayList();
@FXML
private void initialize() {
ObservableList<Diet> diets = DietDAO.getDiets();
diets.forEach(diet -> checkBoxes.add(new CheckBox(diet.getName())));
//checkboxes added in parent Flowpane
parent.getChildren().addAll(checkBoxes);
}
}
Any suggestions? Thanks
Upvotes: 0
Views: 2121
Reputation: 2278
You can use JavaFX's really nice Bindings
-class!
Try this:
okButton.disableProperty().bind(
Bindings.createBooleanBinding(
()->!checkBoxes.stream().anyMatch(CheckBox::isSelected),
checkBoxes.stream().map(x->x.selectedProperty()).toArray(Observable[]::new)
)
);
This creates a new Binding, which will listen on every checkbox and then call the given function to calculate the value of your property. Additional reading here: Bindings
Regarding your comment: I don't know how much you can edit your Diet class, but if you can, there is a very simple way to display your checkboxes and add the button-binding. Take a look at the following sample:
ListView<Diet> dietsView = new ListView<>(diets);
dietsView.setCellFactory(CheckBoxListCell.forListView(diet ->
diet.selectedProperty()));
btn.disableProperty().bind(
Bindings.createBooleanBinding(
() -> !diets.stream().anyMatch(diet->diet.isSelected()),
diets.stream().map(x->x.selectedProperty())
.toArray(Observable[]::new)
)
);
add this to Diet class:
private final BooleanProperty selected = new SimpleBooleanProperty();
public final BooleanProperty selectedProperty() {
return this.selected;
}
public final boolean isSelected() {
return this.selectedProperty().get();
}
public final void setSelected(final boolean on) {
this.selectedProperty().set(on);
}
Upvotes: 2
Reputation: 82491
You need to add listeners to all the selected
properties of the CheckBox
es. Every time one of the property changes, modify the Button
's disable
property, if necessary. BTW: Making checkBoxes
observable doesn't seem necessary:
private List<CheckBox> checkBoxes;
@FXML
private void initialize() {
ObservableList<Diet> diets = DietDAO.getDiets();
checkBoxes = new ArrayList<>(diets.size());
ChangeListener<Boolean> listener = (o, oldValue, newValue) -> {
if (newValue) {
// activate button since at least one CheckBox is selected
okButton.setDisable(false);
} else {
// disable button, if the last CheckBox was unselected
for (CheckBox cb : checkBoxes) {
if (cb.isSelected()) {
return; // don't do anything, if there still is a selected CheckBox
}
}
okButton.setDisable(true);
}
};
for (Diet diet : diets) {
CheckBox cb = new CheckBox(diet.getName());
cb.selectedProperty().addListener(listener);
checkBoxes.add(cb);
}
//checkboxes added in parent Flowpane
parent.getChildren().addAll(checkBoxes);
}
Upvotes: 0