在JavaFX中使用ObjectBinding进行双向绑定 [英] Bidirectional binding with ObjectBinding in JavaFX

查看:365
本文介绍了在JavaFX中使用ObjectBinding进行双向绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的bean具有一些相关的属性。例如,这个bean有一个名为 discountRate 的属性,另一个名为 discountValue 的属性。 discountRate是应用于销售的折扣的百分比(%)。 discountValue是应用于销售的折扣的价值($)。由于用户可以通知百分比或值,并且我需要将两个值存储在数据库中,所以JavaFX双向绑定可以解决问题,但是您可以想像这些值是相关的但不一致。我尝试解决这个问题在双方创建绑定:

  public class ExampleBean {

private ObjectProperty< ; BigDecimal> discountValue;
private ObjectProperty< BigDecimal>折扣率;

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() 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();
}
返回discountRate;
}
}

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

解决方案

需要监听字段的更改,但是如果侦听器已被触发,请保持跟踪,以免在无尽循环中再次触发。灵感来自JavaFX的实际代码,反编译这里

  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& BigDecimal oldValue,BigDecimal newValue){
if(!changing){
try {
changing = true;
discountValue.set(newValue.multiply(getTotalValue()新的BigDecimal(100),RoundingMode.HALF_DOWN));
}
finally {
changing = false;
}
}
}
});
}

这是简单而繁琐的;如果您广泛使用此功能,您可以将内部 ChangeListener 重构为某些常见类型或其他一些聪明的解决方案。



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

  public static void main(String [] args){
ExampleBean e = new ExampleBean();

System.out.println(设置率为50%);
e.discountRateProperty()。set(new BigDecimal(50.0));
System.out.println( - > value =+ e.getDiscountvalue());

System.out.println(设置值为25);
e.discountValueProperty()。set(new BigDecimal(25.0));
System.out.println( - > rate =+ e.getDiscountRate()+%);
}


I have a simple bean that has some properties related with each other. For example, this bean has a property called discountRate and another called discountValue. The discountRate is the percentage (%) of discount applied to a sale. The discountValue is the value($) of discount applied to a sale. As the user can inform either the percentage or the value and I need store the two values in the database, a JavaFX bidirectional binding would solve the problem, however, as you can imagine, these values are correlated but aren't the same. I tried solve this problem creating bindings in the two sides:

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

As you could see, I'm trying calculate the percentage when the value is setted, and calculate the value when the rate is setted. The binding I tried above can't be bound, as this will enter in a eternal loop. Is there a way I can do a binding to solve this problem, or I need do the calculation inside setters?

解决方案

You will need to listen to changes to the fields but keep track if the listener has been fired, so as not to fire again in endless loops. Inspiration was the actual code from JavaFX, decompiled 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;
                }
            }
        }
    });
}

This is simplistic and cumbersome; if you are using this feature extensively, you could refactor the inner ChangeListeners to some common type, or some other clever solution.

I tested the code above with the following main (you wil have to provide a BigDecimal getTotalValue() method, in my case I just returned a constant 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() + "%");
}

这篇关于在JavaFX中使用ObjectBinding进行双向绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆