2013-12-20 4 views
13

У меня есть простой компонент, который имеет некоторые свойства, связанные друг с другом. Например, этот компонент имеет свойство, называемое discountRate, а другое - discountValue. DiscountRate - процент (%) скидки, применяемой к продаже. DiscountValue - это значение ($) скидки, применяемое к продаже. Поскольку пользователь может сообщить либо процент, либо значение, и мне нужно сохранить два значения в базе данных, двунаправленное связывание JavaFX могло бы решить проблему, однако, как вы можете себе представить, эти значения коррелированы, но не совпадают. Я попытался решить эту проблему, создавая привязки в двух сторонах:Двунаправленная привязка с ObjectBinding в 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; 
    } 
} 

Как вы можете видеть, я пытаюсь вычислить процент, когда значение выставиться, и вычислить значение, когда скорость выставиться. Связывание, которое я пробовал выше, не может быть связано, так как это войдет в вечный цикл. Есть ли способ сделать привязку для решения этой проблемы, или мне нужно сделать расчет внутри сеттеров?

ответ

9

Вам нужно будет послушать изменения в полях, но следить за тем, чтобы слушатель был уволен, чтобы не стрелять снова в бесконечные циклы. Вдохновение было фактическим кодом 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; 
       } 
      } 
     } 
    }); 
} 

Это упрощенно и громоздко; если вы широко используете эту функцию, вы можете реорганизовать внутренний ChangeListener на какой-то общий тип или какое-нибудь другое умное решение.

Я тестировал код выше со следующим основным (нужно будет предоставить метод 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() + "%"); 
} 
+2

Я переработан класс для создания пользовательских двунаправленную привязок как вы предположили. Я разместил его здесь: [Индивидуальные двунаправленные привязки в JavaFX] (http://wittcarl.deneb.uberspace.de/wordpress/customized-bidirectional-bindings-in-javafx/) –

+0

@cw «спасибо за блог - это именно то, что Я искал! – kleopatra

Смежные вопросы