FXML/JavaFX 中的多个但有限的复选框

Multiple, but limited, CheckBoxes in FXML/JavaFX

我正在尝试找到一种使用复选框的方法,让用户可以从三项列表中选择两项,然后让剩余的复选框变为禁用状态,直到取消选中其他复选框。我有一个 ChangeListener 附加到所有三个复选框,所以我可以在选择两个复选框时注册,但我不知道如何将 "other" box/boxes 定位到 disable/enable 它们。

ChangeListener checkboxlistener = new ChangeListener() {
int i = 0;
        @Override
        public void changed(ObservableValue observable, Object oldValue, Object newValue) {


            if((boolean) observable.getValue() == true) {

                i++;
                System.out.println(i);
            } else {
                i--;
                System.out.println(i);
            }
            if(i == 2) {
                //What should I put here, if anything?//
            }
        }

};
    checkbox1.selectedProperty().addListener(checkboxlistener);
    checkbox2.selectedProperty().addListener(checkboxlistener);
    checkbox3.selectedProperty().addListener(checkboxlistener);

}

保留选中复选框和未选中复选框的集合。向每个复选框的 selectedProperty 添加一个侦听器,并确保在选择更改时它位于正确的集合中。

然后你可以只观察选中复选框集合的大小,并相应地更新所有未选中复选框的disable状态。

这是一个例子:

MultipleCheckBoxExampleController.java:

package multiplecheckbox;

import javafx.beans.binding.Bindings;
import javafx.beans.binding.IntegerBinding;
import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;

public class MultipleCheckBoxExampleController {
    @FXML
    private CheckBox checkBox1 ;
    @FXML
    private CheckBox checkBox2 ;
    @FXML
    private CheckBox checkBox3 ;
    @FXML
    private Button submitButton ;

    private ObservableSet<CheckBox> selectedCheckBoxes = FXCollections.observableSet();
    private ObservableSet<CheckBox> unselectedCheckBoxes = FXCollections.observableSet();

    private IntegerBinding numCheckBoxesSelected = Bindings.size(selectedCheckBoxes);

    private final int maxNumSelected =  2; 

    public void initialize() {
        configureCheckBox(checkBox1);
        configureCheckBox(checkBox2);
        configureCheckBox(checkBox3);

        submitButton.setDisable(true);

        numCheckBoxesSelected.addListener((obs, oldSelectedCount, newSelectedCount) -> {
            if (newSelectedCount.intValue() >= maxNumSelected) {
                unselectedCheckBoxes.forEach(cb -> cb.setDisable(true));
                submitButton.setDisable(false);
            } else {
                unselectedCheckBoxes.forEach(cb -> cb.setDisable(false));
                submitButton.setDisable(true);
            }
        });


    }

    private void configureCheckBox(CheckBox checkBox) {

        if (checkBox.isSelected()) {
            selectedCheckBoxes.add(checkBox);
        } else {
            unselectedCheckBoxes.add(checkBox);
        }

        checkBox.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
            if (isNowSelected) {
                unselectedCheckBoxes.remove(checkBox);
                selectedCheckBoxes.add(checkBox);
            } else {
                selectedCheckBoxes.remove(checkBox);
                unselectedCheckBoxes.add(checkBox);
            }

        });

    }

}

MultipleCheckBoxExample.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>

<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="multiplecheckbox.MultipleCheckBoxExampleController"
     alignment="center" spacing="5">

    <padding>
        <Insets top="10" bottom="10" left="10" right="10" />
    </padding>

    <CheckBox fx:id="checkBox1" text="Choice 1" />
    <CheckBox fx:id="checkBox2" text="Choice 2" />
    <CheckBox fx:id="checkBox3" text="Choice 3" />
    <Button fx:id="submitButton" text="Submit" />
</VBox>

Main.java:

package multiplecheckbox;

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.fxml.FXMLLoader;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            VBox root = FXMLLoader.load(getClass().getResource("MultipleCheckBoxExample.fxml"));
            Scene scene = new Scene(root,400,400);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

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