2014-05-05 55 views
1

如何在JavaFX中雙向綁定嵌套屬性?如何在JavaFX中雙向綁定嵌套屬性?

例如,我有具有化子性質prop1prop2,這反過來又具有屬性value二者的對象p

如何將它們綁定爲雙向,以便它們將約束相等?

package tests.javafx.beans.binding; 

import javafx.beans.property.SimpleDoubleProperty; 
import javafx.beans.property.SimpleObjectProperty; 

public class Try_BindNested { 

    public static class Nested { 

     private SimpleDoubleProperty value = new SimpleDoubleProperty(); 

     public double getValue() { 
      return value.get(); 
     } 

     public void setValue(double value) { 
      this.value.set(value); 
     } 

     public SimpleDoubleProperty valueProperty() { 
      return value; 
     } 

    } 


    public static class Parent { 

     private SimpleObjectProperty<Nested> prop1 = new SimpleObjectProperty<Nested>(); 

     private SimpleObjectProperty<Nested> prop2 = new SimpleObjectProperty<Nested>(); 

     public Nested getProp1() { 
      return prop1.get(); 
     } 

     public void setProp1(Nested prop1) { 
      this.prop1.set(prop1); 
     } 

     public SimpleObjectProperty<Nested> prop1Property() { 
      return prop1; 
     } 

     public Nested getProp2() { 
      return prop2.get(); 
     } 

     public void setProp2(Nested prop1) { 
      this.prop2.set(prop1); 
     } 

     public SimpleObjectProperty<Nested> prop2Property() { 
      return prop2; 
     } 

    } 

    public static void main(String[] args) { 


     Parent p = new Parent(); 

     // how to bind bidirectional p.prop1.value = p.prop2.value? 


    } 

} 

回答

5

假設你要處理變爲「中間」屬性(即p.prop2.value如果你做p.setProp1(...);更新),那麼有沒有辦法直接綁定的做到這一點;你必須使用一對聽衆。

使用標準JavaFX的屬性API:

ObservableDoubleValue prop1Value = Bindings.selectDouble(p.prop1Property(), "value"); 
ObservableDoubleValue prop2Value = Bindings.selectDouble(p.prop2Property(), "value"); 
prop1Value.addListener(new ChangeListener<Number>() { 
    @Override 
    public void changed(ObservableValue<? extends Number> ov, Number oldVal, Number newValue) { 
     p.getProp2().setValue(newValue); 
    } 
}); 
prop2Value.addListener(new ChangeListener<Number>() { 
    @Override 
    public void changed(ObservableValue<? extends Number> ov, Number oldVal, Number newValue) { 
     p.getProp1().setValue(newValue); 
    } 
}); 

Bindings.select方法是有點難看(它們依賴於反射和不是類型安全);此外,在早期的JavaFX 8版本中,如果任何中間屬性爲空(儘管根據API文檔支持的用例),它們會發出各種警告。如果這成爲問題,您可以查看EasyBind framework。不過,你仍然需要這裏的「雙聽衆」成語。

對於這種情況沒有「內置」雙向綁定的原因是它對於如何更新屬性是不明確的。一般情況下,您可能需要類似p.getProp1().setValue(newVal);的東西,或者您可能想要更改中間屬性:p.setProp1(new Nested(newVal));

最後,您可能需要小心使用浮點類型來執行此操作。上述代碼無法遞歸遞歸的原因在於DoubleProperty中的set方法會在通知更改偵聽器之前檢查確實發生了更改。如果該值涉及任何計算,則可能會產生舍入錯誤,從而創建屬性檢查相等性檢查失敗的情況,因此最終可能會出現StackOverflowError錯誤。如果你的價值屬性做任何事情不是簡單的存儲值比較複雜,你可能想調用的公差後衛setValue

private static final double TOLERANCE = 1e-16 ; // or some other suitable small number 

prop1Value.addListener(new ChangeListener<Number>() { 
    @Override 
    public void changed(ObservableValue<? extends Number> ov, Number oldVal, Number newValue) { 
     if (Math.abs(p.getProp2.getValue() - newVal) > TOLERANCE) { 
      p.getProp2().setValue(newValue); 
     } 
    } 
}); 
在其他方向

和類似。