Define a node call inside a JavaFX change listener

I need to check multiple text fields when changing text. Validation is exactly the same, so I decided to use one procedure. I cannot use onInputMethodTextChanged because I need to perform validation even if the control has no focus. So I added 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, when performing the check, there is no way to find out which TextField caused the change. How can I get this information?

+6
source share
3 answers

There are two ways:

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

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

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

A more reliable way would be to create a listener class as an inner class instead of an anonymous class and keep 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)); 

and etc.

+10
source
 @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(); } } 
0
source

I had a similar problem, but I could not get a solution from this answer. So, I thought I'd make a sample program that could help the next person better understand. The button will not be activated until all text fields have numerical inputs.

Main:

 /** * * @author blj0011 */ public class DoubleFieldValidator extends Application { @Override public void start(Stage stage) throws Exception { Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml")); Scene scene = new Scene(root); stage.setScene(scene); stage.show(); } /** * @param args the command line arguments */ public static void main(String[] args) { launch(args); } } 

Controller:

 import java.net.URL; import java.util.ArrayList; import java.util.Random; import java.util.ResourceBundle; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Button; import javafx.scene.control.TextField; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.VBox; /** * * @author blj0011 */ public class FXMLDocumentController implements Initializable { @FXML private Button btnMain; @FXML private AnchorPane apScrollPane; ObservableList<TextField> textFieldContainer = FXCollections.observableArrayList(); ArrayList<Boolean> fieldValidatorContainer = new ArrayList(); @FXML private void handleButtonAction(ActionEvent event) { System.out.println("You pressed me!"); } @Override public void initialize(URL url, ResourceBundle rb) { // TODO btnMain.setDisable(true);//Disable button until all fields are validated Random random = new Random(); //create textfields on the fly for(int i = 0; i < random.nextInt(20) + 1; i++)//creates 1 to 20 textfields { textFieldContainer.add(new TextField());//create textfield and add it to container fieldValidatorContainer.add(false);//set corresponding validator container to false; } VBox vbox = new VBox(); vbox.getChildren().addAll(textFieldContainer); apScrollPane.getChildren().add(vbox); //create a listener for each textfield for(int i = 0; i < textFieldContainer.size(); i++) { textFieldContainer.get(i).textProperty().addListener((observable, oldValue, newValue) -> { System.out.println("observable: " + observable); //loop though the textfieldContainer to find right container for(int t = 0; t < textFieldContainer.size(); t++) { //look for right container. once found get container index t if(textFieldContainer.get(t).textProperty().equals((observable))) { System.out.println("object t: " + t); fieldValidatorContainer.set(t, fieldValidator(newValue)) ;//set validator container at corresponding index fieldValidatorCheck(); //run the check to see if the button should be enabled or not. } } }); } } //used to check if field has double value or not. private boolean fieldValidator(String data){ try { double d = Double.parseDouble(data); return true; } catch(NumberFormatException ex) { return false; } } //used to disable or enable update button private void fieldValidatorCheck() { for(int i = 0; i < fieldValidatorContainer.size(); i++) { System.out.println("poition " + i + ": " + fieldValidatorContainer.get(i)); if(fieldValidatorContainer.get(i) == false) { btnMain.setDisable(true); return; } } btnMain.setDisable(false); } } 

FXML:

 <?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.ScrollPane?> <?import javafx.scene.layout.AnchorPane?> <AnchorPane id="AnchorPane" prefHeight="330.0" prefWidth="459.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="doublefieldvalidator.FXMLDocumentController"> <children> <Button fx:id="btnMain" layoutX="284.0" layoutY="144.0" onAction="#handleButtonAction" text="Click Me!" /> <ScrollPane fx:id="spMain" layoutX="30.0" layoutY="30.0" prefHeight="297.0" prefWidth="200.0"> <content> <AnchorPane fx:id="apScrollPane" minHeight="0.0" minWidth="0.0" prefHeight="279.0" prefWidth="200.0" /> </content> </ScrollPane> </children> </AnchorPane> 
0
source

All Articles