【问题标题】:Bidirectional binding with ObjectBinding in JavaFXJavaFX 中与 ObjectBinding 的双向绑定
【发布时间】:2014-01-09 07:28:02
【问题描述】:

我有一个简单的 bean,它有一些相互关联的属性。例如,这个 bean 有一个名为 discountRate 的属性和另一个名为 discountValue 的属性。 discountRate 是应用于销售的折扣百分比 (%)。 discountValue 是应用于销售的折扣值 ($)。由于用户可以告知百分比或值,并且我需要将这两个值存储在数据库中,因此 JavaFX 双向绑定可以解决问题,但是,正如您可以想象的那样,这些值是相关的,但并不相同。我尝试在两侧创建绑定来解决这个问题:

public class ExampleBean{

    private ObjectProperty<BigDecimal> discountValue;
    private ObjectProperty<BigDecimal> discountRate;

    public BigDecimal getDiscountvalue() {
        return discountValueProperty().getValue();
    }

    public void setDiscountValue(BigDecimal discountvalue) {
        this.discountValueProperty().set(discountvalue);
    }

    public ObjectProperty<BigDecimal> discountValueProperty() {
        if(discountValue==null){
            discountValue=new SimpleObjectProperty<BigDecimal>(new BigDecimal("0.00"));
            discountRate=new SimpleObjectProperty<BigDecimal>(new BigDecimal("0.00"));
            configureDiscountBinding();
        }
        return discountValue;
    }

    private void configureDiscountBinding(){
        discountValue.bind(Bindings.createObjectBinding(new Callable<BigDecimal>() {
            @Override
            public BigDecimal call() throws Exception {
                return getDiscountRate().multiply(getTotalValue()).divide(new BigDecimal("100"));
            }
        }, discountRateProperty()));
        discountRate.bind(Bindings.createObjectBinding(new Callable<BigDecimal>() {
            @Override
            public BigDecimal call() throws Exception {
                return getDiscountValue().multiply(new BigDecimal("100")).divide(getTotalValue());
            }
        }, discountValueProperty()));
    }

    public BigDecimal getDiscountRate() {
        return discountRateProperty().getValue();
    }

    public void setDiscountRate(BigDecimal discountRate) {
        this.discountRateProperty().set(discountRate);
    }

    public ObjectProperty<BigDecimal> discountRateProperty() {
        if(discountRate==null){
            discountRate=new SimpleObjectProperty<BigDecimal>(new BigDecimal("0.00"));
            discountValue=new SimpleObjectProperty<BigDecimal>(new BigDecimal("0.00"));
            configureDiscountBinding();
        }
        return discountRate;
    }
}

如您所见,我正在尝试在设置值时计算百分比,并在设置速率时计算值。我上面尝试的绑定无法绑定,因为这将进入一个永恒的循环。有没有办法可以通过绑定来解决这个问题,或者我需要在 setter 中进行计算?

【问题讨论】:

    标签: java data-binding javafx javafx-2


    【解决方案1】:

    您需要监听字段的更改,但要跟踪监听器是否已被触发,以免在无限循环中再次触发。灵感来自 JavaFX 的实际代码,反编译后的 here

    private void configureDiscountBinding() {
        discountValue.addListener(new ChangeListener<BigDecimal>() {
            private boolean changing;
    
            @Override public void changed(ObservableValue<? extends BigDecimal> observable, BigDecimal oldValue, BigDecimal newValue) {
                if( !changing ) {
                    try {
                        changing = true;
                        discountRate.set(newValue.multiply(new BigDecimal("100")).divide(getTotalValue(), RoundingMode.HALF_DOWN));
                    }
                    finally {
                        changing = false;
                    }
                }
            }
        });
    
        discountRate.addListener(new ChangeListener<BigDecimal>() {
            private boolean changing;
    
            @Override public void changed(ObservableValue<? extends BigDecimal> observable, BigDecimal oldValue, BigDecimal newValue) {
                if( !changing ) {
                    try {
                        changing = true;
                        discountValue.set(newValue.multiply(getTotalValue()).divide(new BigDecimal("100"), RoundingMode.HALF_DOWN));
                    }
                    finally {
                        changing = false;
                    }
                }
            }
        });
    }
    

    这样简单又麻烦;如果您广泛使用此功能,您可以将内部 ChangeListeners 重构为某种常见类型,或其他一些巧妙的解决方案。

    我用下面的 main 测试了上面的代码(你必须提供一个 BigDecimal getTotalValue() 方法,在我的例子中我只是返回一个常量 BigDecimal):

    public static void main(String[] args) {
        ExampleBean e = new ExampleBean();
    
        System.out.println("Setting rate to 50%");
        e.discountRateProperty().set(new BigDecimal(50.0));
        System.out.println("-> value=" + e.getDiscountvalue());
    
        System.out.println("Setting value to 25");
        e.discountValueProperty().set(new BigDecimal(25.0));
        System.out.println("-> rate=" + e.getDiscountRate() + "%");
    }
    

    【讨论】:

    猜你喜欢
    • 2015-03-01
    • 2015-01-19
    • 2017-04-22
    • 1970-01-01
    • 2011-02-16
    • 2016-02-10
    • 2012-07-10
    • 1970-01-01
    相关资源
    最近更新 更多