0

I have 4 CheckBoxes and the user has the possibility to select all of them or neither of them. The order matters, so there are 16 possible different combinations. I would like to have an efficient function that reads the CheckBoxes and returns me a value from 0 to 15 depending on the combination. Is there something already implemented in JavaFX?

EDIT

I am trying to implement the solution of @fabian

 private static int countSelectedCheck(CheckBox[] maskCheckBoxes){

    // print binary
    int value = 0;
    for (int i = 0; i < maskCheckBoxes.length; i++) {
        if (maskCheckBoxes[i].isSelected()) {
            value += (1 << i);
        }
    }
    System.out.println(value);

    return value;
}

but I am getting exceptions.

MPA
  • 355
  • 3
  • 14
  • There are hundreds of possible exceptions in Java. Which ones are you getting? – Zephyr Jun 27 '18 at 12:41
  • `NullPointerException` on the line of the `if` statement in the method right above. – MPA Jun 27 '18 at 12:43
  • 2
    Then my assumption is that `maskCheckBoxes[i]` is `null`... Without seeing the rest of your code or the whole stacktrace, that is just an assumption. – Zephyr Jun 27 '18 at 12:44
  • 1
    https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it/218510#218510 – Zephyr Jun 27 '18 at 12:46
  • @zephyr thanks for your answer I have added my declaration in the comments of the answer. you can check that there. – MPA Jun 27 '18 at 12:47

1 Answers1

1

There would be 16 possibilities, if you want to read the checkbox states as binary number with 4 digits.

If you select all 4 CheckBoxes and consider the order of selection, you get 4! = 24 possibilities. Choosing none is another possibility and if you allow an arbitrary number of CheckBoxes to be chosen, your get another 24 for selecting exactly 3 CheckBoxes and another 12 for selecting exactly 2 CheckBoxes and 4 more for selecting exactly 1 CheckBox summing up to 65 = 24 + 24 + 12 + 4 + 1.

The simplest solution for saving the order of selection would be by storing the CheckBoxes (or values identifying them) in a List.

The following example prints the selection interpreted as binary number and also prints the order of selection.

@Override
public void start(Stage primaryStage) throws IllegalAccessException {
    VBox container = new VBox();
    final List<CheckBox> selectionOrder = new ArrayList<>();
    final int checkBoxCount = 4;

    for (int i = 0; i < checkBoxCount; i++) {
        final CheckBox cb = new CheckBox();
        cb.setUserData(i);
        cb.selectedProperty().addListener((o, oldValue, newValue) -> {
            if (newValue) {
                selectionOrder.add(cb);
            } else {
                selectionOrder.remove(cb);
            }
        });
        container.getChildren().add(cb);
    }

    Button btn = new Button("print");
    btn.setOnAction(evt -> {
        System.out.println(selectionOrder.stream().map(c -> c.getUserData().toString()).collect(Collectors.joining(", ", "{ ", " }")));
        // print binary
        int value = 0;
        for (CheckBox cb : selectionOrder) {
            value |= (1 << ((Integer) cb.getUserData()));
        }
        System.out.println(value);
    });

    container.getChildren().add(btn);

    Scene scene = new Scene(container);
    primaryStage.setScene(scene);
    primaryStage.show();
}

If you don't actually need the order of selection, I'd recommend removing the list, the listener to the selected property and not set the userData and instead store the CheckBoxes in a CheckBox[] array which allows you to do

int value = 0;
for (int i = 0; i < array.length; i++) {
    if (array[i].isSelected()) {
        value |= (1 << i);
    }
}
fabian
  • 80,457
  • 12
  • 86
  • 114
  • I do not need the order of selection, however I need to know which of the 16 combinations is selected by the user (eg: all selected means that my value should be 15, while when no one is selected my value should be 0). I am trying to implement a method with your tips, but I am getting an error. Did you mean this? *check edit in the question* – MPA Jun 27 '18 at 12:34
  • @DavideDiMatteo I just checked the code you posted in the question and it seems to work. Did you assign the `CheckBox`es as the array elements and did you assign a `CheckBox` to every index? Otherwise you may get a `NullPointerException`. – fabian Jun 27 '18 at 12:43
  • maybe the problem is the variable declaration, which i was not super sure. Let's say I already have 4 `CheckBox`es and I want to put them in an array. I did like this: `CheckBox[] maskCheckBoxes = {maskBit0, maskBit1, maskBit2, maskBit3};` where those variables are my `CheckBox`es – MPA Jun 27 '18 at 12:46
  • @DavideDiMatteo Are you sure this is executed ***after*** the variables are assigned non-`null` values? This kind of array creation evaluates the expressions inside the `{}` when the array creation expression is executed. – fabian Jun 27 '18 at 12:49
  • Ok probably that is what I am doing wrong. What is a good formal way to do this kind of assignment? I do not want to do it inside my `static method` – MPA Jun 27 '18 at 12:53
  • @DavideDiMatteo You're creating the `CheckBox`es somewhere. If you're doing this in the `Application.start` method or a similar method you can do the array creation anywhere after the last one of the `CheckBox`es is created. If you're creating the values using a fxml and the code creating the array is inside the controller, use the `initialize` method for creating the array. – fabian Jun 27 '18 at 13:00
  • Ok, that sounds clear. However I am still failing something. I am in your 2nd scenario. I have the values created via `.fxml` and the mapping is doing inside my controller class through `@FXML` tag (eg: `@FXML private CheckBox maskBit0;`). Then what should I do? I also tried, as you said to create `CheckBox[] maskCheckBoxes = new CheckBox[4];` just this and then adding the variables in the `initialize()` method. What am I doing wrong this time? Thank you – MPA Jun 27 '18 at 13:11
  • 1
    Probably `fx:id` is not used correctly or something else went wrong. It would be better to ask a new question about this topic. This has little to do with the original question. Be sure to include a [mcve] (fxml, controller and code invoking the method containing the, if it's not a event handler in the fxml; also the full stacktrace (as code block)). The question may be closed as duplicate pretty soon though. Since you're asking about a NPE, be sure to identify the expression and not ask "How can I fix this exception?" but "Why does this expression yield null?" – fabian Jun 27 '18 at 13:28
  • I found it! a typo on the `fx:id`. Thank you very much – MPA Jun 27 '18 at 14:18