2013-12-14 85 views
6

當需要更改文本時,需要在多個TextField上執行驗證。驗證是完全一樣的,所以我認爲我使用一個單一的程序。我無法使用onInputMethodTextChanged,因爲即使控件沒有焦點,我也需要執行驗證。所以我加了一個ChangeListenertextProperty確定JavaFX更改監聽器內部的調用節點

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觸發了更改。我如何獲得這些信息?

回答

10

有兩種方法:假設你只用TextField的Text屬性註冊這個監聽器

,傳遞到changed(...)方法ObservableValue是到textProperty參考。它有一個getBean()方法,將返回TextField。所以,你可以做

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

這顯然打破(用ClassCastException),如果你註冊超過TextFieldtextProperty其他一些聽衆,但它可以讓你重複使用相同的監聽器實例。

更健壯的方式可能是建立監聽器類作爲一個內部類,而不是匿名類並保持到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 
    } 
} 

然後

this.firstTextField.textProperty().addListener(new TextFieldListener(this.firstTextField)); 

等。

+0

爲了避免出現'ClassCastException',我想你可以期待'Control'而不是'TextField'並檢查Control是否是'TextField',就像'if(mControl instanceof TextField)((TextField)mControl ).doSomething()' –

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(); 
    } 
} 
0

我有一個類似的問題,但無法從gi中派生出解決方案回答。所以,我想我會製作一個示例程序,以幫助下一個人更好地理解。直到所有文本字段都有數字輸入,該按鈕纔會啓用。

主要:

/** 
* 
* @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>