2017-06-01 213 views
1

我正在開發使用JavaFX中,我創建一個GridPane內動態文本字段和有它最初像這樣禁用的按鈕的應用程序:JavaFx:如何比較GridPane中動態創建的TextField的值?

enter image description here

所以,我要的是,如果第1列TextField的值小於第3個的TextField值,按鈕應使這樣的:

enter image description here

但我們說,如果任何列3文本字段值變得小於同一行的第1個文本字段的值,它應該disab樂按鈕,並以紅色顯示的具體文本字段邊緣,當鼠標懸停在該字段應該顯示一些警告:

enter image description here

我創建文本字段是這樣的:

public static GridPane table(int rows){ 
      GridPane table = new GridPane(); 

      for(int i=0; i<rows; i++){ 
      TextField textField1 = new JFXTextField(); 
      textField1.setAlignment(Pos.CENTER); 
      TextField textField2 = new JFXTextField(); 
      textField2.setAlignment(Pos.CENTER); 
      TextField textField3 = new JFXTextField(); 
      textField3.setAlignment(Pos.CENTER); 

      //add them to the GridPane 
      table.add(textField1, 0, i+1); 
      table.add(textField2, 1, i+1); 
      table.add(textField3, 2, i+1); 
     } 
     return table; 
    } 

我之後創建另一種方法來返回組件在特定行和列如下:

public static Node getComponent (int row, int column, GridPane table) { 
     for (Node component : table.getChildren()) { // loop through every node in the table 
      if(GridPane.getRowIndex(component) == row && 
          GridPane.getColumnIndex(component) == column) { 
       return component; 
      } 
     } 

     return null; 
    } 

我試圖做這樣的b UT它不工作(在這裏,我將值轉換成字符串和公正的檢查比較):

private boolean isTextEqual(GridPane table, Button button){ 

     for(Node node : table.getChildren()){ 
      if(node instanceof TextField){ 
       for(int i=1 ; i<=ComboBox().getValue(); i++){ 
        String str = ((TextField)DynamicGridpanes.getComponent (i, 0, table)).getText(); 
        ((TextField)DynamicGridpanes.getComponent (i, 2, table)).textProperty().addListener((obs, old, newV)->{ 
        if(newV.toString()==str){ 
         button.setDisable(false); 
        } 
        else{ 
         button.setDisable(true); 
        } 
       }); 
        } 
       } 
      } 

     return true; 
    } 
+0

你仍然有'DatePicker'和'CheckBox'在你的餐桌? – Yahya

+0

是@Yahya我有。我發佈它就像簡化問題 – Junaid

+0

所以基本上你有三列'TextFields'(後面是對方),他們是'CheckBoxs',然後是'DatePickers'?並且是每個'TextField'列在不同'GridPane'中..你有多少個'GridPane'? – Yahya

回答

1

其實它不是那麼容易做到你想要什麼,因爲你的代碼都需要進行重構(代碼並不意味着做這種先進的要求,但它的優良的基本要求你有)。然而,你可以做這樣的事情:

首先,定義一個全球變量與無效TextFieldlast row index從這裏你就斷定這將改變邊框顏色爲更新ONE無效TextField同時):

public static int textFieldIndex = -1; 

與方法的幫助下,你已經有了getComponent (int row, int column, GridPane table),創建另一個靜態方法我們檢查ALLTextFields具有有效值一次:

/** 
* This method to check at run time with every change in any TextField 
* if the corresponding TextField has a valid value(i.e contains number and 
* the first TextField value is less than the second) 
* @param table 
* @param numRows 
*/ 
private static boolean hasValidValue(GridPane table, int numRows){ 
    // cycle through every row in the table 
    // and compare every two TextFields 
    for(int i=0; i<numRows; i++){ 
     try{ // try because user may enters a non-number input (to avoid crash) 
     // the first TextField is always at column index 0 , the second at column index 3 
     if(Integer.parseInt(((TextField)(getComponent (i, 0, table))).getText())> 
      Integer.parseInt(((TextField)(getComponent (i, 3, table))).getText())){ 
      // before returning false 
      textFieldIndex = i; // update at which row the TextField is less 
      return false; 
      } 
     }catch(NumberFormatException e){ // if it contains invalid input(non-digit) 
      return false; 
     } 
    } 
    return true; 
} 

現在,您需要使用上面的方法在validateTable()方法,並做一些調整:

// pass the comboBox.getValue() to the third parameter 
private void validateTable(GridPane table, Button button, int numRows) { 

    for(Node textField : table.getChildren()){ 
     if(textField instanceof TextField){ 
     ((TextField)textField).textProperty().addListener((obs, old, newV)->{ 
      // first of all remove the red border from the invalid TextField (if any) 
      // we know that via textFieldIndex which should be -1 if there is no lesser 
      // actually it's a pain 
      if(textFieldIndex!=-1){ 
      ((TextField) getComponent(textFieldIndex, 3, table)).setStyle(""); 
      } 
      if(isAllFilled(table)){ // if all filled (you already have this method) 
      if(hasValidValue(table,numRows)){ // check for validity 
       button.setDisable(false); // then make the button active again 
      } 
      else{// if it's not a valid value 
        // re-style the TextField which has lesser value 
       ((TextField) getComponent(textFieldIndex, 3, table)). 
             setStyle("-fx-border-color: red;"); 
        button.setDisable(true); 
      } 
      } 
      else{ 
       button.setDisable(true); 
      } 
     }); 
    } 
    } 
} 

現在,在您tabPane ChangeListener添加方法的第三段(因爲您已經擁有它,您只需添加值ComboBox

tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>(){ 
    .... 
    .... 
    .... 
    // I think you have here anchorPane not containerB in the original code 
    validateTable((GridPane) containerB.getChildren().get(0), test, comboBox.getValue()); 
} 

測試

Test

+0

@Junaid一切都好嗎? – Yahya

+0

Idk @Yahya但「hasValidValue」總是返回true – Junaid

+0

是@Yahya它現在正在工作,但它一次顯示一個紅色邊框,就像第二列中有更多值,第一列中沒有顯示紅色邊框。 ,那麼我們可以實現這樣的事情嗎?這不是什麼大問題,但如果可以實現,它會更好。 – Junaid

1

您可以創建在創建文本字段做驗證綁定。這將避免需要瀏覽網格窗格的子節點,這看起來不太健壯。

聲明布爾綁定的數組(會有每行一個):

private BooleanBinding[] rowValidationBindings ; 

然後,你可以做

public static GridPane table(int rows){ 
    GridPane table = new GridPane(); 

    rowValidationBindings = new BooleanBinding[rows]; 

    for(int i=0; i<rows; i++){ 
     TextField textField1 = new JFXTextField(); 
     textField1.setAlignment(Pos.CENTER); 
     TextField textField2 = new JFXTextField(); 
     textField2.setAlignment(Pos.CENTER); 
     TextField textField3 = new JFXTextField(); 
     textField3.setAlignment(Pos.CENTER); 

     rowValidationBindings[i] = Bindings.createBooleanBinding(
      () -> { 
       if (textField1.getText().matches("\\d+") && 
        textField3.getText().matches("\\d+")) { 
        int value1 = Integer.parseInt(textField1.getText()); 
        int value3 = Integer.parseInt(textFIeld3.getText()); 
        return value3 > value1 ; 
       } else { 
        return false ; 
       } 
      }, textField1.textProperty(), textField2.textProperty() 
     ); 

     //add them to the GridPane 
     table.add(textField1, 0, i+1); 
     table.add(textField2, 1, i+1); 
     table.add(textField3, 2, i+1); 
    } 

    button.disableProperty().bind(Bindings.createBooleanBinding(
     () -> ! Stream.of(rowValidationBindings).allMatch(BooleanBinding::get), 
     rowValidationBindings 
    )); 

    return table; 
} 

您還可以添加樣式到文本字段直接在在for循環:

textField3.styleProperty().bind(Bindings 
    .when(rowValidationBindings[i]) 
    .then("") 
    .otherwise("-fx-border-color: red")); // or whatever you are using for style 

和工具提示:

Tooltip tooltip = new Tooltip(); 
tooltip.textProperty().bind(Bindings.concat("Value must be greater than ",textField1.textProperty())); 
textField3.tooltipProperty().bind(Bindings 
    .when(rowValidationBindings[i]) 
    .then((Tooltip)null) 
    .otherwise(tooltip)); 
+0

說實話,我會極大地重構這段代碼,創建一個表示每行的類,並添加用於添加到網格窗格並檢索值的方法。然後公開該類的'ObservableBooleanValue valid'(以及提取值的方法)。然後,您可以保留該類的實例的List,並且可以很容易地爲該按鈕創建綁定。 –

+0

您可以詳細說明一下這個「創建一個代表每一行的類」是什麼意思 – Junaid

+0

@Junaid您不必這麼做,它只會簡化您的代碼。我的意思是創建一個包含三個文本字段的類,一個「valid」字段和你需要的方法(例如'void addToGridPaneRow(int row)','String getText1()'等)。但是發佈的解決方案應該可行。 。 –