JavaFX按钮的disableProperty绑定到多个布尔绑定

JavaFX按钮的disableProperty绑定到多个布尔绑定,java,javafx,binding,Java,Javafx,Binding,我有几个文本字段和一个提交按钮。我希望禁用我的按钮,除非所有文本字段都已验证。下面是我的布尔绑定代码: BooleanBinding firstNameValidation, middleNameValidation, lastNameValidation, usernameValidation, passwordValidation, retypePasswordValidation, emailValidation, phoneNumberValidatio

我有几个文本字段和一个提交按钮。我希望禁用我的按钮,除非所有文本字段都已验证。下面是我的布尔绑定代码:

        BooleanBinding firstNameValidation, middleNameValidation, lastNameValidation, 
        usernameValidation, passwordValidation, retypePasswordValidation, emailValidation, phoneNumberValidation;

        firstNameValidation = Bindings.createBooleanBinding(()->{
            if(employee.setFirstName(txtFirstName.getText()) == 0){
                piFirstName.setProgress(100);
                return true;
            } else {
                piFirstName.setProgress(0);
                return false;
            }
        }, txtFirstName.textProperty());

        middleNameValidation = Bindings.createBooleanBinding(()->{
            if(employee.setMiddleName(txtMiddleName.getText()) == 0){
                piMiddleName.setProgress(100);
                return true;
            } else {
                piMiddleName.setProgress(0);
                return false;
            }
        }, txtMiddleName.textProperty());
btnSetPermissions.disableProperty().bind(firstNameValidation.not().or(middleNameValidation.not()).or(lastNameValidation.not())
                .or(usernameValidation.not()).or(passwordValidation.not()).or(retypePasswordValidation.not())
                .or(emailValidation.not()).or(phoneNumberValidation.not()));
…等等

以下是我尝试将submit按钮的disableProperty绑定到BooleanBindings的方式:

        BooleanBinding firstNameValidation, middleNameValidation, lastNameValidation, 
        usernameValidation, passwordValidation, retypePasswordValidation, emailValidation, phoneNumberValidation;

        firstNameValidation = Bindings.createBooleanBinding(()->{
            if(employee.setFirstName(txtFirstName.getText()) == 0){
                piFirstName.setProgress(100);
                return true;
            } else {
                piFirstName.setProgress(0);
                return false;
            }
        }, txtFirstName.textProperty());

        middleNameValidation = Bindings.createBooleanBinding(()->{
            if(employee.setMiddleName(txtMiddleName.getText()) == 0){
                piMiddleName.setProgress(100);
                return true;
            } else {
                piMiddleName.setProgress(0);
                return false;
            }
        }, txtMiddleName.textProperty());
btnSetPermissions.disableProperty().bind(firstNameValidation.not().or(middleNameValidation.not()).or(lastNameValidation.not())
                .or(usernameValidation.not()).or(passwordValidation.not()).or(retypePasswordValidation.not())
                .or(emailValidation.not()).or(phoneNumberValidation.not()));
它可以工作,但如果第一个条件返回false,则由于OR操作,它不会检查其余条件


我似乎找不到解决办法。任何帮助都将不胜感激。

您的功能混合太多了。将其分为以下组成部分:

firstNameValidation = Bindings.createBooleanBinding(() -> {
    String firstName = txtFirstName.getText();
    if (/* firstName is valid */) {
        return true ;
    } else {
        return false ;
    }
}, txtFirstName.textProperty());

employee.firstNameProperty().bind(txtFirstName.textProperty());
// if you want employee.firstName to change only if the name is valid,
// use a listener here instead of the binding above:
txtFirstName.textProperty().addListener((obs, oldText, newText) -> {
    if (firstNameValidation.get()) {
        employee.setFirstName(newText);
    }
});

piFirstName.bind(Bindings.when(firstNameValidation).then(100).otherwise(0));

// similarly for other properties...

// then (this logic is equivalent to yours, but easier to read imho)

btnSetPermissions.disableProperty().bind(
    (firstNameValidation.and(middleNameValidation)
     .and(userNameValidation).and(passwordValidation)
     .and(retypePasswordValidation).and(emailValidation)
     .and(phoneNumberValidation)
    ).not());
注意:当然,您可以通过以通常的方式将任何重复的内容移动到方法中来减少代码:

private BooleanBinding createValidationBinding(
        TextField field, Predicate<String> validationRule, 
        StringProperty boundValue, ProgressIndicator indicator) {

    BooleanBinding validation = Bindings.createBooleanBinding(() -> {
        String value = field.getText();
        return validationRule.test(value);
    }, field.textProperty());

    field.textProperty().addListener((obs, oldText, newText) -> {
        if (binding.get()) {
            boundValue.set(newText);
        }
    });

    indicator.progressProperty().bind(Bindings.when(validation).then(100).otherwise(0));

    return validation ;
}

其他领域也是如此。

我个人就是这么做的:

btnSetPermissions.disableProperty.bind(Bindings.createBooleanBinding(() -> {
    if (!validateFirstName() ||
        !validateMiddleName() /* and so on */)
        return true;
    else return false;
}, firstNameProperty(), middleNameProperty() /* and other properties*/ ));

public boolean validateFirstName() {
    // Your validation logic
}

public boolean validateMiddleName() {
    // Your validation logic
}

/* Other validation methods */

不需要创建那么多BindingExpression对象,您可以轻松使用| |和&&等条件运算符,这将保证尽可能跳过非必要的检查。

如果第一个条件返回false,为什么要检查其他条件?意思是,如果第一个条件为false,则应禁用按钮,因为if语句中有ProgressIndicator。我希望他们动态地指示输入何时正确,即使文本字段没有失去焦点。也许我应该改用ChangeListener。set方法返回值是非常不寻常和不标准的。你能解释一下employee.setFirstName的作用吗?看起来您试图在绑定中做的工作太多了,应该将它们分成不同的功能部分。set方法验证输入,如果输入正确,则返回0,否则返回错误代码。我将尝试将验证与set方法分开。不过,在本例中,OP还有几个其他值绑定到各个验证绑定…@James_D Oh,我错过了关于ProgressIndicator的部分。谢谢。我将从集合方法中分离验证,并使用您的建议。