Franz Kohnle
Franz Kohnle

Reputation: 23

JavaFX TextField react on userinput, but not on setText()

How do I write a ChangeListener for a JavaFX Textfield, which reacts only on userinput, but not on the setText method?

textField.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable,
            String oldValue, String newValue) {

        // code is executed, when user changes text,
        // but also, when setText(..) is called
    }
});

Upvotes: 2

Views: 1845

Answers (1)

James_D
James_D

Reputation: 209398

Questions like this always make me think your design is somehow wrong. The text represents some data; you are registering a listener because you're interested in when the data changes - it shouldn't really matter why it changed. If it does matter, you probably need a property to represent your data that is different from the property inherent to the text field.

The last point gives a possible solution, too:

final TextField textField = new TextField(); // or injected from FXML, etc

final StringProperty text = new SimpleStringProperty(textField.getText());
text.addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> obs, String oldValue, String newValue) {
        textField.setText(newValue);
    }
});

textField.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> obs, String oldValue, String newValue) {
        if (! newValue.equals(text.get())) { // textField's text was changed directly (i.e. by user)
            // perform whatever action you need...

            // update the text property so the two remain equal:
            text.set(newValue);
        }
    }
});

The important thing now is that you never call textField.setText(...), but always call text.set(...) instead. That results in a programmatic call to textField.setText(...) via the first listener. This invokes the second listener, but at this point the new value for the text field will be the same as the value for the custom property.

On the other hand, if the user types in the text field, that creates a call (internal to the text field) to textField.textProperty().set(...), which invokes your listener. Here the new text field value is different to your custom property value, so the main part of the code there is invoked.

Upvotes: 2

Related Questions