Determine calling node inside JavaFX change listener
Asked Answered
B

4

8

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?

Barram answered 14/12, 2013 at 16:11 Comment(0)
E
14

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.

Extrasystole answered 14/12, 2013 at 17:33 Comment(2)
to avoid ClassCastException, I think you can expect Control rather than TextField and check if the Control is a TextField, something like if(mControl instanceof TextField) ((TextField) mControl).doSomething()Crumby
I want to give a more general solution. This will work with StringProperty,, BooleanProperty etc.: ((ReadOnlyProperty<?>)observable).getBean()Mendicity
M
0
@Override
public void changed(ObservableValue observableValue, Object o, Object n) {
    try {
        StringProperty textProperty = (StringProperty) observableValue ;
        TextField textField = (TextField) textProperty.getBean();

        if (textField == textFieldChannel1) {

        } else if (textField == textFieldChannel2) {

        } else if (textField == textFieldChannel3) {

        }
    } catch (Exception e) {
        //e.printStackTrace();
    }
}
Miter answered 21/1, 2016 at 20:9 Comment(0)
B
0

Just use valueProperty instead ;)

this.firstTextField.valueProperty().addListener(textListener);
this.secondTextField.valueProperty().addListener(textListener);
this.thirdTextField.valueProperty().addListener(textListener);
Bernardabernardi answered 19/6, 2018 at 20:17 Comment(1)
Tried this and it doesn't look like valueProperty() exists for a TextField.Quelpart
T
0

It has a simple solution.

public void setListener(TextField textField) {
    BiConsumer<TextField, String> check = (tField, newValue) -> {
        // Do validation
    };
    textField.textProperty().addListener((ov, o, n)->check.accept(textField, n));
}
Teodoor answered 7/1, 2021 at 11:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.