【问题标题】:JavaFx 8 Bidirectional bindingJavaFx 8 双向绑定
【发布时间】:2015-03-01 01:09:40
【问题描述】:

以下代码触发java.lang.RuntimeException: A bound value cannot be set

public class Test {

   public static void main( String[] args ) {
      final DoubleProperty amount = new SimpleDoubleProperty( 100_000.00 );
      final DoubleProperty rate   = new SimpleDoubleProperty();
      final DoubleProperty part   = new SimpleDoubleProperty();
      rate.bind( part.divide  ( amount.getValue()));
      part.bind( rate.multiply( amount.getValue()));
      rate.set( 0.025 );//<<----------------------------------- Here is the cause
      System.out.println( "Part: " + part.get());
      part.set( 1200 );
      System.out.println( "Rate: " + rate.get());
   }
}

使用Bindings.bindBidirectional 可能是一个解决方案,但我不知道如何。

【问题讨论】:

    标签: java data-binding javafx javafx-8


    【解决方案1】:

    一种可能的解决方案是创建 InvalidationListeners - 不使用绑定。

    它是如何工作的:

    • 设置速率会导致速率无效。这是设置部分的时间,因此也是无效的。
    • 依次设置速率不会再次触发 InvalidationListener。这就是它的定义方式。

    .

    public static void main(String[] args) {
        final DoubleProperty amount = new SimpleDoubleProperty(100_000.00);
        final DoubleProperty part = new SimpleDoubleProperty();
        final DoubleProperty rate = new SimpleDoubleProperty();
    
        part.addListener(new InvalidationListener() {
            @Override
            public void invalidated(Observable observable) {
                System.out.println("part is invalid");
                rate.set(part.get() / amount.get());
            }
        });
    
        rate.addListener(new InvalidationListener() {
            @Override
            public void invalidated(Observable observable) {
                System.out.println("rate is invalid");
                part.set(rate.get() * amount.get());
            }
        });
    
        System.out.println("setting rate");
        rate.set(0.025);
        System.out.println("Part: " + part.get()); //2500
    
        System.out.println("setting part");
        part.set(1200);
        System.out.println("Rate: " + rate.get()); //0.012
    }
    

    上面代码的输出是:

    setting rate
    rate is invalid
    part is invalid
    Part: 2500.0
    setting part
    part is invalid
    rate is invalid
    Rate: 0.012
    

    【讨论】:

    • 如何避免无限通知循环?
    • 这不会发生。触发 InvalidationListener 的定义是:如果变量已经无效,则不触发。我学到了这个here。寻找“但如果绑定已经无效,则失效监听器将不会再次触发”
    • 是的!这个方案看起来不错,我会把它翻译成我自己的提案
    【解决方案2】:

    一个简单的静态方法,一个自制的NumberBiBinding就可以了:

    public final class NumberBiBinding {
    
       public static void bind(
          Property<Number> operand1,
          NumberBinding    operator1,
          Property<Number> operand2,
          NumberBinding    operator2  )
       {
          assert operand1 != operand2;
          operand1.addListener( o -> operand2.setValue( operator1.getValue()));
          operand2.addListener( o -> operand1.setValue( operator2.getValue()));
       }
    }
    
    public final class Test {
    
       public static void main( String[] args ) {
          final DoubleProperty amount = new SimpleDoubleProperty( 100_000.00 );
          final DoubleProperty rate   = new SimpleDoubleProperty();
          final DoubleProperty part   = new SimpleDoubleProperty();
    
          NumberBiBinding.bind(
             rate, rate.multiply( amount ),
             part, part.divide  ( amount ));
    
          System.out.println( "Amount: " + amount.get());
          rate.set( 0.025 );
          System.out.println(
            "Part is " + part.get() + " when rate is set to " + rate.get());
          part.set( 1200 );
          System.out.println(
             "Rate is " + rate.get() + " when part is set to " + part.get());
       }
    }
    

    输出:

    Amount: 100000.0
    Part is 2500.0 when rate is set to 0.025
    Rate is 0.012 when part is set to 1200.0
    

    【讨论】:

      猜你喜欢
      • 2015-01-19
      • 2017-04-22
      • 2014-01-09
      • 1970-01-01
      • 2019-12-04
      • 1970-01-01
      • 1970-01-01
      • 2014-12-12
      • 1970-01-01
      相关资源
      最近更新 更多