有效地在监听器中使用监听器?

时间:2017-05-24 07:00:57

标签: java javafx

如果我在表单的上下文中有多个TextField,那么如何提交'按钮保持禁用状态,直到TextFields任意数字不为空?

如果文本字段中只有一个TextFieldChangeListener一起出现,可以很简单地完成此操作,但如何为 x TextField& #39; S?
其中 x 是一个数字> 1.

一个TextField示例
如果字段为空,则在.setDisable()上使用ChangeListener实现按钮的TextField方法。

这表现为:

  • 当文本字段为空时,按钮已禁用
  • 当文本字段包含
  • 时,按钮启用

......正如所料。

如果两个字段使用相同的监听器(如下所示),则它们表现得好像彼此独立。
例如如果任何一个包含某些内容,则启用该按钮:

public void someMethod(){
    Dialog dialog = new Dialog();
    dialog.getDialogPane().getButtonTypes().addAll(ButtonType.APPLY, ButtonType.CANCEL);

    TextField textField1 = new TextField();
    textField1.setPromptText("field1");
    TextField textField2 = new TextField();
    textField2.setPromptText("field2");


    // add fields to gridpane
    GridPane gridPane = new GridPane();
    gridPane.add(textField1,0,0);
    gridPane.add(textField2,0,1);

    // add grid to dialog pane
    dialog.getDialogPane().setContent(gridPane);

    Node applyButton = dialog.getDialogPane().lookupButton(ButtonType.APPLY);
    applyButton.setDisable(true);

    ChangeListener<String> myChangeListener = new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
            applyButton.setDisable(newValue.trim().isEmpty());
        }
    };

    textField1.textProperty().addListener(myChangeListener);
    textField2.textProperty().addListener(myChangeListener);

    dialog.showAndWait();
}

如果使用相同的过程将独立的Listener添加到每个字段,情况也是如此:

textField1.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        applyButton.setDisable(newValue.trim().isEmpty());
    }
});


textField2.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        applyButton.setDisable(newValue.trim().isEmpty());
    }
});

多次尝试
多重的一个解决方案是简单地“分层”。彼此内的听众。这样做符合预期,在启用按钮之前,两个TextField都必须包含某些内容

    textField1.textProperty().addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
            // add listener to textField 2
            textField2.textProperty().addListener(new ChangeListener<String>() {
                @Override
                public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                    applyButton.setDisable(newValue.trim().isEmpty());

                    // ... add listener to textField x
                }
            });
        }
    });

这个过程看起来效率很低! 如果我有20 TextFields怎么办?我应该分层吗? 20深?

这是唯一的方法吗?如果没有,该过程如何更有效?

1 个答案:

答案 0 :(得分:1)

您不需要在其他侦听器中添加额外的侦听器 - 无论先前的更改是否发生,您都希望观察更改。

相反,您必须检查每次更改时整个输入的有效性(所有文本字段是否为空)。这可以通过将所有TextField传递给一个方法来公平地完成:

private void setButtonTextFieldListeners(Button button, TextField... textFields) {
    ChangeListener<String> listener = (observable, oldValue, newValue) -> {
        for (int i=0; i<textFields.length; i++) {
            if (textFields[i].getText()==null || textFields[i].getText().trim().isEmpty()) {
                button.setDisable(true);
                return;
            }
        }
        button.setDisable(false);
    }
    for (TextField textField : textFields) {
        textField.textProperty().addListener(listener);
    }
}

或者,您可以BooleanExpression and建立所有条件,然后将按钮的disable属性绑定到其否定位置:

BooleanExpression b = textField1.textProperty().isNotEmpty()
                  .and(textField2.textProperty().isNotEmpty())
                  .and(...);
// b is True if and only if ALL text fields are not-empty. The button should be disabled when this ISN'T the case (enabled when b is True).
button.disableProperty().bind(b.not());