确定JavaFX更改侦听器中的调用节点

确定JavaFX更改侦听器中的调用节点,java,javafx-2,Java,Javafx 2,当文本更改时,我需要对几个文本字段执行验证。验证是完全相同的,所以我想我使用一个过程。我无法使用onInputMethodTextChanged,因为即使控件没有焦点,我也需要执行验证。因此,我在textProperty中添加了一个ChangeListener private TextField firstTextField; private TextField secondTextField; private TextField thirdTextField; protected void

当文本更改时,我需要对几个文本字段执行验证。验证是完全相同的,所以我想我使用一个过程。我无法使用onInputMethodTextChanged,因为即使控件没有焦点,我也需要执行验证。因此,我在textProperty中添加了一个ChangeListener

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);
}
private TextField firstTextField;
私有TextField secondTextField;
私有文本字段thirdTextField;
受保护的void初始化(){
ChangeListener textListener=新的ChangeListener(){
@凌驾
公共空隙改变(观察值有两种方式:

假设您仅使用
TextField
的text属性注册此侦听器,传递到
changed(…)
方法的
observeValue
是对该
textProperty
的引用。它有一个
getBean()
方法,该方法将返回
TextField
。因此您可以这样做

StringProperty textProperty = (StringProperty) observable ;
TextField textField = (TextField) textProperty.getBean();
如果您使用
TextField
textProperty
以外的内容注册侦听器,这显然会中断(使用
ClassCastException
),但它允许您重用相同的侦听器实例

更可靠的方法可能是将侦听器类创建为内部类而不是匿名类,并保留对
文本字段的引用:

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
  }
}

等等。

我有一个类似的问题,但无法从给定的答案中得出解决方案。因此,我想我可以制作一个示例程序,帮助下一个人更好地理解。在所有文本字段都有数字输入之前,按钮将无法启用

主要内容:

控制器:

import java.net.URL;
导入java.util.ArrayList;
导入java.util.Random;
导入java.util.ResourceBundle;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.event.ActionEvent;
导入javafx.fxml.fxml;
导入javafx.fxml.Initializable;
导入javafx.scene.control.Button;
导入javafx.scene.control.TextField;
导入javafx.scene.layout.ancorpane;
导入javafx.scene.layout.VBox;
/**
*
*@author blj0011
*/
公共类FXMLDocumentController实现可初始化的{
@FXML专用按钮btnMain;
@FXML-私人锚烷胶囊;
ObservableList textFieldContainer=FXCollections.observableArrayList();
ArrayList fieldValidatorContainer=新的ArrayList();
@FXML
私有无效把手按钮操作(ActionEvent事件){
System.out.println(“你逼我了!”);
}
@凌驾
公共void初始化(URL、ResourceBundle rb){
//待办事项
btnMain.setDisable(true);//禁用按钮,直到验证所有字段
随机=新随机();
//动态创建文本字段
for(int i=0;i{
System.out.println(“可观察:+可观察”);
//循环遍历textfieldContainer以找到正确的容器
对于(int t=0;t
FXML:


只需使用valueProperty


它有一个简单的解决方案

public void setListener(TextField textField) {
    BiConsumer<TextField, String> check = (tField, newValue) -> {
        // Do validation
    };
    textField.textProperty().addListener((ov, o, n)->check.accept(textField, n));
}
public void setListener(TextField TextField){
双消费者检查=(t字段,新值)->{
//验证
};
textField.textProperty().addListener((ov,o,n)->check.accept(textField,n));
}

为了避免
ClassCastException
,我认为您可以期望
控件
而不是
TextField
,并检查
控件是否是
TextField
,类似于
if(TextField的mControl instanceof TextField)((TextField)mControl.doSomething()
我想给出一个更通用的解决方案。这将适用于StringProperty、BooleanProperty等:
((ReadOnlyProperty)observable)。getBean()尝试了这个方法,但看起来valueProperty()不存在
@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();
    }
}
/**
 *
 * @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);
    }    
}
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's 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);
    }
}
<?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>
this.firstTextField.valueProperty().addListener(textListener);
this.secondTextField.valueProperty().addListener(textListener);
this.thirdTextField.valueProperty().addListener(textListener);
public void setListener(TextField textField) {
    BiConsumer<TextField, String> check = (tField, newValue) -> {
        // Do validation
    };
    textField.textProperty().addListener((ov, o, n)->check.accept(textField, n));
}