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