java - JavaFX 中的多个 boolean 值绑定(bind)

标签 java javafx

我正在尝试将一个复选框绑定(bind)到多个复选框,如下所示:

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”有多个项目时允许双向组绑定(bind)。这样当我选择我的包时,“面板”将自动被选中,或者如果我选择“面板”,所有的“pkg”将被选中/取消选择。我被困在了:

panel.selectedProperty().bind(binder);

得到了

"JavaFX Application Thread" java.lang.RuntimeException: CheckBox.selected : A bound value cannot be set.

因为我为“ Binder ”做了一个单向绑定(bind)。有没有一种方法可以执行与此等效的操作?:

panel.selectedProperty().bindBidirectional(binder);

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

最佳答案

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

这是一种实现方式:

// 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);
    }
}

关于java - JavaFX 中的多个 boolean 值绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32192963/

相关文章:

java - controlsfx 的新版本controlsfx-8.20.7 中缺少 CommandLink

javafx-2 - 如何在 javafx2 中的 TextField 上的 focusOut 上打印一些内容

java - Android 使用 Java 和 REST 连接到 MySQL

java强制扩展类

java - 使用 'java-library' 和 'api' 而不是 'compile' 时获取 Gradle 中的运行时库列表

java - 是否可以禁用日志文件中的 TimingLogger 行?

java - 试图将 Java 变量传递给 sql 字符串

JavaFX 最小化未修饰阶段

java - 选择哪个 ChoiceBox-Event?

java - 如何从 JavaFX 应用程序读取 X11 剪贴板?