Search code examples
javajavafx-2

Determine calling node inside JavaFX change listener


I need to perform validation on several TextFields when text is changed. The validation is exactly the same, so I thought I use a single procedure. I can't use onInputMethodTextChanged because I need to perform validation even when control does not have focus. So I added a ChangeListener to textProperty.

private TextField firstTextField;
private TextField secondTextField;
private TextField thirdTextField;

protected void initialize() {
    ChangeListener<String> textListener = new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> observable,
                String oldValue, String newValue) {
            // Do validation
        }
    };

    this.firstTextField.textProperty().addListener(textListener);
    this.secondTextField.textProperty().addListener(textListener);
    this.thirdTextField.textProperty().addListener(textListener);
}

However, while performing validation, there is no way to know which TextField triggered the change. How can I obtain this information?


Solution

  • There are two ways:

    Assuming you only register this listener with the text property of a TextField, the ObservableValue passed into the changed(...) method is a reference to that textProperty. It has a getBean() method which will return the TextField. So you can do

    StringProperty textProperty = (StringProperty) observable ;
    TextField textField = (TextField) textProperty.getBean();
    

    This will obviously break (with a ClassCastException) if you register the listener with something other than the textProperty of a TextField, but it allows you to reuse the same listener instance.

    A more robust way might be to create the listener class as an inner class instead of an anonymous class and hold a reference to the TextField:

    private class TextFieldListener implements ChangeListener<String> {
      private final TextField textField ;
      TextFieldListener(TextField textField) {
        this.textField = textField ;
      }
      @Override
      public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        // do validation on textField
      }
    }
    

    and then

    this.firstTextField.textProperty().addListener(new TextFieldListener(this.firstTextField));
    

    etc.