ayvango
ayvango

Reputation: 5977

Restrict text input inside combobox

I need to restrict text input inside combobox with positive numbers. I've searched stackoverflow for this and found similar question: Recommended way to restrict input in JavaFX textfield

The only difference is that the mentioned question addresses bare textfield. The answer approved by the javafx designers is to extend the TextField class and override couple of methods: replaceText and replaceSelection. This hack does not work with combobox: TextField instance if stored inside and is avaiable as read-only property named editor.

So what is the recommended way to restrict text input inside javafx combobox?

Upvotes: 0

Views: 1883

Answers (3)

Jonatan Stenbacka
Jonatan Stenbacka

Reputation: 1864

Since this question question never got a proper answer I'm adding a solution I've implemented that restricts the user to input that matches a regular expression and is shorter than a particular length (this is optional). This is done by adding a ChangeListener to the editor TextField. Any input that doesn't match will not get written into the editor TextField.

This example restricts the user to a maximum of two numeric characters.

ComboBox<Integer> integerComboBox = new ComboBox<Integer>();
integerComboBox.setEditable(true);
integerComboBox.getEditor().textProperty()
            .addListener(new ChangeListener<String>() {

                // The max length of the input
                int maxLength = 2;

                // The regular expression controlling the input, in this case we only allow number 0 to 9.
                String restriction = "[0-9]";

                private boolean ignore;

                @Override
                public void changed(
                        ObservableValue<? extends String> observableValue,
                        String oldValue, String newValue) {
                    if (ignore || newValue == null) {
                        return;
                    }

                    if (newValue.length() > maxLength) {
                        ignore = true;
                        integerComboBox.getEditor().setText(
                                newValue.substring(0, maxLength));
                        ignore = false;
                    }

                    if (!newValue.matches(restriction + "*")) {
                        ignore = true;
                        integerComboBox.getEditor().setText(oldValue);
                        ignore = false;
                    }
                }
            });

Upvotes: 1

Jens-Peter Haack
Jens-Peter Haack

Reputation: 1907

How about decouplign the Text editor from the ComboBox and link their values?

    HBox combo = new HBox();

    TextField editor = new TextField();

    ComboBox<String> first = new ComboBox<String>();
    first.setItems(myChoices);
    first.setButtonCell(new ComboBoxListCell<String>(){
        @Override public void updateItem(String s, boolean empty) {
            super.updateItem(s, empty);
            setText(null);
        }
    });

    editor.textProperty().bindBidirectional(first.valueProperty());

    combo.getChildren().addAll(editor, first);
    box.getChildren().addAll(combo);

Now you have full conroll over the TextField allowing to override any methods etc.

Upvotes: 0

Jens-Peter Haack
Jens-Peter Haack

Reputation: 1907

You might register a check method on the editor property to check if any input is accpetable.

Here I allow editing, but draw a red frame if values are not in the items list.

ObservableList<String> myChoices = FXCollections.observableArrayList();

void testComboBoxCheck(VBox box) {
    myChoices.add("A");
    myChoices.add("B");
    myChoices.add("C");

    ComboBox<String> first = new ComboBox<String>();
    first.setItems(myChoices);
    first.setEditable(true);
    first.editorProperty().getValue().textProperty().addListener((v, o, n) -> {
        if (myChoices.contains(n.toUpperCase())) {
            first.setBackground(new Background(new BackgroundFill(Color.rgb(30,30,30), new CornerRadii(0), new Insets(0))));
        } else {
            first.setBackground(new Background(new BackgroundFill(Color.RED, new CornerRadii(0), new Insets(0))));
        }
    });

    box.getChildren().addAll(first);
}

enter image description here enter image description here

Upvotes: 0

Related Questions