user4786688
user4786688

Reputation:

JavaFX Three-State Checkbox

Given:

I have a javafx.scene.control.CheckBox and I would like to allow 3-states instead of only 2 (selected and not selected).

I read about indeterminate state.

According to JavaDocs http://docs.oracle.com/javafx/2/api/javafx/scene/control/CheckBox.html#allowIndeterminateProperty

checked: indeterminate == false, checked == true

unchecked: indeterminate == false, checked == false

undefined: indeterminate == true

Problem:

I need to allow from indeterminate to selected only once

CheckBox checkbox = new CheckBox("Indeterminate");
    checkbox.setAllowIndeterminate(true);
    checkbox.setIndeterminate(true);
    checkbox.setSelected(false);
    checkbox.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                if (checkbox.isIndeterminate()) {
                    checkbox.setSelected(true);
                    checkbox.setIndeterminate(false);
                    checkbox.setAllowIndeterminate(false);
                    checkbox.setText("Checked");
                } else if (checkbox.isSelected()) {
                    checkbox.setSelected(false);
                    checkbox.setText("Unchecked");
                } else if (!checkbox.isSelected()) {
                    checkbox.setSelected(true);
                    checkbox.setText("Checked");
                }
            }
        });

Interestingly, when I click on the checkbox for the first time, it goes directly to the else if (checkbox.isSelected()) block!!!

Question:

WHAT???! HOW? Why isn't this working?

What I need is that if it is initially indeterminate, then on the first click, it should become checked. And continue on more clicks: checked -> unchecked, unchecked -> checked, ...

Else if it initially not indeterminate (ie selected or not selected), then it should behave normally: checked -> unchecked, unchecked -> checked, ...

Upvotes: 1

Views: 2635

Answers (1)

DVarga
DVarga

Reputation: 21799

When you set allowIndeterminateProperty to true, what you actually do is to allow the CheckBox to cycle all three states:

Determines whether the user toggling the CheckBox should cycle through all three states: checked, unchecked, and undefined. If true then all three states will be cycled through; if false then only checked and unchecked will be cycled.

In your case it should be set to false, as you want it just to cycle between checked and unchecked.

Then if you set indeterminateProperty initially either true or false the CheckBox will just cycle checked and unchecked states.

The reason why your CheckBox enters the isSelected branch is the cycle defined in the quote: checked -> unchecked -> undefined -> checked -> .... Your CheckBox is in undefined state because of checkbox.setIndeterminate(true); and the next state is checked.

Example

This CheckBox is initially undefined then it cycles checked and unchecked.

CheckBox checkBox = new CheckBox();
checkBox.indeterminateProperty().set(true);
checkBox.setAllowIndeterminate(false);

checkBox.selectedProperty().addListener((obs, oldVal, newVal) -> {
    if(newVal)
        System.out.println("Checked");
    else
        System.out.println("Unchecked");
});

Upvotes: 1

Related Questions