2015-01-02 7 views
2

Следующий код пожаров java.lang.RuntimeException: A bound value cannot be set:JavaFX 8 Двунаправленный связывание

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 может быть решение, но я не знаю, как.

ответ

2

Возможным решением может быть создание 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 
+0

Как избежать бесконечного цикла уведомления? – Aubin

+1

Этого не происходит. Определение запуска InvalidationListener: не запускать, если переменная уже недействительна. Я узнал об этом [здесь] (http://docs.oracle.com/javase/8/javafx/properties-binding-tutorial/binding.htm#JFXBD107). Ищите «Но если привязка уже недействительна, приемник недействительности не будет запускаться снова» – chris

+0

Да! Это решение выглядит хорошо, я переведу его в свое предложение – Aubin

0

простой статический метод, домашнее 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 
Смежные вопросы