JavaFX中的多个布尔绑定

我试图将复选框绑定到多个复选框,如下所示:

private void bindPanelToPackages(CheckBox panel, CheckBox ...pkg){ BooleanProperty panelBinding = null; BooleanBinding binder = null; for(CheckBox p: pkg){ if(panelBinding == null){ panelBinding = p.selectedProperty(); } else{ binder = panelBinding.and(p.selectedProperty()); } } if(binder != null){ panel.selectedProperty().bind(binder); } else if(panelBinding != null){ panel.selectedProperty().bindBidirectional(panelBinding); } } 

我想要的是当’pkg’有多个项时允许双向组绑定。 这样当我选择我的包时,会自动选择’面板’,或者如果我选择’面板’,将选择/取消选择所有’pkg’。 我被困在:

。panel.selectedProperty()结合(粘合剂);

得到了

“JavaFX Application Thread”java.lang.RuntimeException:CheckBox.selected:无法设置绑定值。

因为我为’binder’做了单向绑定。 有没有办法可以执行与此相同的操作?:

。panel.selectedProperty()bindBidirectional(粘合剂);

我似乎无法在文档中找到它,或者我没有找到正确的地方。 谢谢!

条件“选中所有复选框”只能表示为BooleanBinding ,而不能表示为BooleanProperty 。 基本上,问题是使该条件为false是没有明确定义的:有很多方法可以做到这一点(即,取消选择所有复选框的任何非空子集)。 因此,您不能使用双向绑定:您必须在两个条件中的每一个上使用侦听器。

这是一个实现:

 // must keep a reference to the Binding to prevent premature // garbage collection: BooleanBinding allSelected ; private void bindPanelToPackages(CheckBox pane, CheckBox... packages) { // BooleanBinding that is true if and only if all check boxes in packages are selected: allSelected = Bindings.createBooleanBinding(() -> // compute value of binding: Stream.of(packages).allMatch(CheckBox::isSelected), // array of thing to observe to recompute binding - this gives the array // of all the check boxes' selectedProperty()s. Stream.of(packages).map(CheckBox::selectedProperty).toArray(Observable[]::new)); // update pane's selected property if binding defined above changes allSelected.addListener((obs, wereAllSelected, areAllNowSelected) -> pane.setSelected(areAllNowSelected)); // use an action listener to listen for a direct action on pane, and update all checkboxes // in packages if this happens: pane.setOnAction(e -> Stream.of(packages).forEach(box -> box.setSelected(pane.isSelected()))); } 

和一个SSCCE:

 import java.util.stream.IntStream; import java.util.stream.Stream; import javafx.application.Application; import javafx.beans.Observable; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; import javafx.scene.Scene; import javafx.scene.control.CheckBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class MultipleCheckBoxSelection extends Application { private BooleanBinding allSelected ; @Override public void start(Stage primaryStage) { CheckBox selectAll = new CheckBox("Select all"); int numBoxes = 5 ; CheckBox[] boxes = IntStream .rangeClosed(1, numBoxes) .mapToObj(i -> new CheckBox("Item "+i)) .toArray(CheckBox[]::new); bindPanelToPackages(selectAll, boxes); VBox root = new VBox(10, selectAll); root.setStyle("-fx-padding: 15;"); Stream.of(boxes).forEach(box -> box.setStyle("-fx-padding: 0 0 0 10;")); Stream.of(boxes).forEach(root.getChildren()::add); Scene scene = new Scene(root, 250, 400); primaryStage.setScene(scene); primaryStage.show(); } private void bindPanelToPackages(CheckBox pane, CheckBox... packages) { // BooleanBinding that is true if and only if all check boxes in packages are selected: allSelected = Bindings.createBooleanBinding(() -> // compute value of binding: Stream.of(packages).allMatch(CheckBox::isSelected), // array of thing to observe to recompute binding - this gives the array // of all the check boxes' selectedProperty()s. Stream.of(packages).map(CheckBox::selectedProperty).toArray(Observable[]::new)); // update pane's selected property if binding defined above changes allSelected.addListener((obs, wereAllSelected, areAllNowSelected) -> pane.setSelected(areAllNowSelected)); // use an action listener to listen for a direct action on pane, and update all checkboxes // in packages if this happens: pane.setOnAction(e -> Stream.of(packages).forEach(box -> box.setSelected(pane.isSelected()))); } public static void main(String[] args) { launch(args); } }