JavaFx:如何在GridPane中比较动态创建的TextFields的值?

时间:2017-06-01 16:04:34

标签: java javafx javafx-2 javafx-8

我正在使用JavaFx开发一个应用程序,我在其中创建一个GridPane中的动态TextFields,并且有一个Button最初被禁用,如下所示:

enter image description here

所以我想要的是如果第1列TextFields值小于第3列TextFields值,则按钮应该像这样启用:

enter image description here

但是,如果第3列TextField值中的任何一个值变得小于同一行的第1列TextField值,它应该禁用按钮并以红色显示特定的TextField边框,并且当鼠标悬停在该字段上时应显示一些警告:< / p>

enter image description here

我正在创建像这样的TextField:

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

我尝试这样做,但它不起作用(我在这里将值转换为字符串并仅仅进行比较):

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

2 个答案:

答案 0 :(得分: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));

答案 1 :(得分:1)

实际上做你想做的事情并不容易,因为你需要重构的代码(代码不是要做这样的高级要求,但它对你的基本要求很好 )。但是,您可以这样做:

首先,定义一个全局变量,使用无效last row index的{​​{1}}进行更新(从此处您将得出结论,这将会改变一次无效TextField的边框颜色):

TextField

现在借助您已拥有public static int textFieldIndex = -1; 的方法,创建另一个静态方法,以检查 ALL getComponent (int row, int column, GridPane table)是否同时具有有效值:< /强>

TextFields

现在您需要在/** * 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

<强>测试

Test