我需要在更改文本时对多个TextField执行验证。验证完全相同,所以我认为我使用一个程序。我无法使用 onInputMethodTextChanged ,因为即使控件没有焦点,我也需要执行验证。所以我将 ChangeListener 添加到 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);
}
但是,在执行验证时,无法知道哪个TextField触发了更改。我如何获得这些信息?
答案 0 :(得分:12)
有两种方法:
假设您只使用TextField
的text属性注册此侦听器,则传递到ObservableValue
方法的changed(...)
是对textProperty
的引用。它有一个getBean()
方法,它将返回TextField
。所以你可以做到
StringProperty textProperty = (StringProperty) observable ;
TextField textField = (TextField) textProperty.getBean();
如果您使用ClassCastException
的{{1}}之外的其他内容注册侦听器,这显然会中断(使用textProperty
),但它允许您重用相同的侦听器实例。
更强大的方法可能是将侦听器类创建为内部类而不是匿名类,并保留对TextField
的引用:
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
}
}
等
答案 1 :(得分: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();
}
}
答案 2 :(得分:0)
我有类似的问题,但无法从给定的答案中得出解决方案。所以,我想我会制作一个示例程序,可以帮助下一个人更好地理解。在所有文本字段都有数字输入之前,该按钮才会启用。
主:
/**
*
* @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);
}
}
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>
答案 3 :(得分:0)
只需使用 valueProperty 即可;)
this.firstTextField.valueProperty().addListener(textListener);
this.secondTextField.valueProperty().addListener(textListener);
this.thirdTextField.valueProperty().addListener(textListener);
答案 4 :(得分:0)
它有一个简单的解决方案。
public void setListener(TextField textField) {
BiConsumer<TextField, String> check = (tField, newValue) -> {
// Do validation
};
textField.textProperty().addListener((ov, o, n)->check.accept(textField, n));
}