java - 如何在 JavaFX 中双向绑定(bind)嵌套属性?

标签 java binding javafx javabeans

如何在 JavaFX 中双向绑定(bind)嵌套属性?

例如,我有一个对象 p,它具有属性 prop1prop2,它们又具有属性 value两者。

如何双向绑定(bind)它们,使它们约束相等?

package tests.javafx.beans.binding;

import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;

public class Try_BindNested {

    public static class Nested {

        private SimpleDoubleProperty value = new SimpleDoubleProperty();

        public double getValue() {
            return value.get();
        }

        public void setValue(double value) {
            this.value.set(value);
        }

        public SimpleDoubleProperty valueProperty() {
            return value;
        }

    }


    public static class Parent {

        private SimpleObjectProperty<Nested> prop1 = new SimpleObjectProperty<Nested>();

        private SimpleObjectProperty<Nested> prop2 = new SimpleObjectProperty<Nested>();

        public Nested getProp1() {
            return prop1.get();
        }

        public void setProp1(Nested prop1) {
            this.prop1.set(prop1);
        }

        public SimpleObjectProperty<Nested> prop1Property() {
            return prop1;
        }

        public Nested getProp2() {
            return prop2.get();
        }

        public void setProp2(Nested prop1) {
            this.prop2.set(prop1);
        }

        public SimpleObjectProperty<Nested> prop2Property() {
            return prop2;
        }

    }

    public static void main(String[] args) {


        Parent p = new Parent();

        // how to bind bidirectional p.prop1.value = p.prop2.value?


    }

}

最佳答案

假设您要处理对“中间”属性的更改(即,如果您执行 p.setProp1(...);,则更新 p.prop2.value; ) 那么就没有办法直接用绑定(bind)来做到这一点;你必须使用一对听众。

使用标准的 JavaFX 属性 API:

ObservableDoubleValue prop1Value = Bindings.selectDouble(p.prop1Property(), "value");
ObservableDoubleValue prop2Value = Bindings.selectDouble(p.prop2Property(), "value");
prop1Value.addListener(new ChangeListener<Number>() {
   @Override
   public void changed(ObservableValue<? extends Number> ov, Number oldVal, Number newValue) {
        p.getProp2().setValue(newValue);
   }
});
prop2Value.addListener(new ChangeListener<Number>() {
   @Override
   public void changed(ObservableValue<? extends Number> ov, Number oldVal, Number newValue) {
        p.getProp1().setValue(newValue);
   }
});

Bindings.select 方法有点难看(它们依赖于反射并且类型不安全);此外,在早期的 JavaFX 8 版本中,如果任何中间属性为空,它们会发出各种警告(尽管根据 API 文档,这是受支持的用例)。你可能会看看 EasyBind framework如果这成为一个问题。不过,您在这里仍然需要“双重监听器”习语。

在这种情况下没有“内置”双向绑定(bind)的原因是它对如何更新属性不明确。通常,您可能需要类似 p.getProp1().setValue(newVal); 的东西,或者您可能想要更改中间属性:p.setProp1(new Nested(newVal)) ;

最后,您可能需要小心处理浮点类型。上面的代码没有以无限递归结束的原因是 DoubleProperty 中的 set 方法会在通知更改监听器之前检查是否确实发生了更改。如果该值涉及任何计算,您可能会冒舍入错误的风险,从而导致属性的相等性检查错误地失败,因此您可能会得到一个不错的 StackOverflowError。如果您的 value 属性做的事情比简单地存储值更复杂,您可能希望使用容差来保护对 setValue 的调用:

private static final double TOLERANCE = 1e-16 ; // or some other suitable small number

prop1Value.addListener(new ChangeListener<Number>() {
   @Override
   public void changed(ObservableValue<? extends Number> ov, Number oldVal, Number newValue) {
        if (Math.abs(p.getProp2.getValue() - newVal) > TOLERANCE) {
            p.getProp2().setValue(newValue);
        }
   }
});

反之亦然。

关于java - 如何在 JavaFX 中双向绑定(bind)嵌套属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23476586/

相关文章:

java - 奇怪的行为类型

forms - laravel 表单模型绑定(bind) - 日期格式

Spring 使用 SAML 进行 http-artifact 绑定(bind)

JavaFX 概括 GridPane 列约束

java - 我的过渡不起作用

java - 数据不会填充 ListView

java - 在一个正方形内生成 N 个点(均匀)

java - try/catch block 在 Action 监听器中不起作用

asp.net-mvc - 如何使用 ASP.NET MVC 将字典绑定(bind)到一组复选框?

javafx - 相当于 javafx 中的 awt Desktop?