Reputation: 23
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
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