2013-06-04 58 views
2

我有一個SimpleElement類,它有一個權重字段,第二個有一個SimpleElement列表和一個權重字段,它取決於包含在列表中的所有其他SimpleElements的權重總和。任何人有任何想法如何通過綁定來做到這一點?
我的代碼:JavaFX:如何綁定列表中的多個屬性?

import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleIntegerProperty; 

public class SimpleElement { 

IntegerProperty weight; 

public SimpleElement() { 
    weight = new SimpleIntegerProperty(); 
} 

public int getWeight() { 
    return weight.get(); 
} 

public void setWeight(int weight) { 
    this.weight.set(weight); 
} 

public IntegerProperty weightProperty() { 
    return weight; 
} 

} 

import java.util.ArrayList; 
import java.util.List; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleIntegerProperty; 

public class RootElement { 

List<SimpleElement> elements; 
IntegerProperty weight; 

public RootElement() { 
    elements = new ArrayList<>(); 
    weight = new SimpleIntegerProperty(); 
} 

public void addelements(SimpleElement element) { 

    elements.add(element); 

} 

} 
+0

考慮Tomas Mikula的[EasyBind](https://github.com/TomasMikula/EasyBind)。 –

回答

1

RootElement類可以被重寫以創建綁定到每個SimpleElement,將它們添加了:

public class RootElement { 
    List<SimpleElement> elements; 
    IntegerProperty weight; 
    NumberBinding binding; 

    public RootElement() { 
     elements = new ArrayList<>(); 
     weight = new SimpleIntegerProperty(); 
    } 

    public void addelements(SimpleElement element) { 
     elements.add(element); 

     if (binding == null) { 
      binding = element.weightProperty().add(0); 
     } else { 
      binding = binding.add(element.weightProperty()); 
     } 

     weight.bind(binding); 
    } 

    public Integer getWeight() { 
     return weight.get(); 
    } 

    public ReadOnlyIntegerProperty weightProperty() { 
     return weight; 
    } 
} 

使用示例:

public static void main(String[] args) { 
    SimpleElement se1 = new SimpleElement(); 
    SimpleElement se2 = new SimpleElement(); 
    SimpleElement se3 = new SimpleElement(); 
    RootElement root = new RootElement(); 

    root.addelements(se1); 
    root.addelements(se2); 
    root.addelements(se3); 

    root.weightProperty().addListener(new ChangeListener<Number>() { 
     @Override 
     public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { 
      System.out.println(newValue); 
     } 
    }); 

    se1.setWeight(3); 
    se2.setWeight(2); 
    se1.setWeight(4); 
} 

代碼的執行上述生產:

1

Crferreira的回答使用流利API來構建綁定的鏈,我覺得很難清潔和保持何時可以移除或替換對象。最好使用低級API。

儘管JavaFX API中有大量預構建綁定的東西,但是當其中一個元素獲取新屬性值時,ListBinding不會失效。所以你必須創建你的IntegerBinding子類,它可以監聽列表中的更改,並重新綁定到新的屬性本身。

基於類似answer的代碼。

import java.util.ArrayList; 
import java.util.List; 
import javafx.beans.binding.IntegerBinding; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.FXCollections; 
import javafx.collections.ListChangeListener; 
import javafx.collections.ObservableList; 

class RootElement { 

    ObservableList<SimpleElement> elements = FXCollections.observableList(new ArrayList<SimpleElement>()); 

    IntegerBinding totalWeight; 

    public RootElement() { 

     totalWeight = new SumOfWeightsForListOfSimpleElementsIntegerBinding(elements); 

    } 

    public void addElement(SimpleElement element) { 

     elements.add(element); 

    } 

    public void removeElement(SimpleElement element) { 

     elements.remove(element); 

    } 

    public Integer getWeigth() { 
     return totalWeight.getValue(); 
    } 

} 

class SimpleElement { 

    IntegerProperty weight; 

    public SimpleElement() { 
     this(0); 
    } 

    public SimpleElement(Integer weight) { 
     this.weight = new SimpleIntegerProperty(weight); 
    } 

    public int getWeight() { 
     return weight.get(); 
    } 

    public void setWeight(int weight) { 
     this.weight.set(weight); 
    } 

    public IntegerProperty weightProperty() { 
     return weight; 
    } 

} 

class SumOfWeightsForListOfSimpleElementsIntegerBinding extends IntegerBinding { 

    // Reference to our observable list 
    private final ObservableList<SimpleElement> boundList; 

    // Array of currently observed properties of elements of our list 
    private IntegerProperty[] observedProperties = {}; 

    // Listener that has to call rebinding in response of any change in observable list 
    private final ListChangeListener<SimpleElement> BOUND_LIST_CHANGE_LISTENER 
      = (ListChangeListener.Change<? extends SimpleElement> change) -> { 
       refreshBinding(); 
      }; 

    SumOfWeightsForListOfSimpleElementsIntegerBinding(ObservableList<SimpleElement> boundList) { 
     this.boundList = boundList; 
     boundList.addListener(BOUND_LIST_CHANGE_LISTENER); 
     refreshBinding(); 
    } 

    @Override 
    protected int computeValue() { 
     int i = 0; 
     for (IntegerProperty bp : observedProperties) { 
      i += bp.get(); 
     } 

     return i; 
    } 

    @Override 
    public void dispose() { 
     boundList.removeListener(BOUND_LIST_CHANGE_LISTENER); 
     unbind(observedProperties); 
    } 

    private void refreshBinding() { 
     // Clean old properties from IntegerBinding's inner listener 
     unbind(observedProperties); 

     // Load new properties  
     List<IntegerProperty> tmplist = new ArrayList<>(); 
     boundList.stream().map((boundList1) -> boundList1.weightProperty()).forEach((integerProperty) -> { 
      tmplist.add(integerProperty); 
     }); 

     observedProperties = tmplist.toArray(new IntegerProperty[0]); 

     // Bind IntegerBinding's inner listener to all new properties 
     super.bind(observedProperties); 

     // Invalidate binding to generate events 
     // Eager/Lazy recalc depends on type of listeners attached to this instance 
     // see IntegerBinding sources 
     this.invalidate(); 
    } 
} 

public class Main { 

    public static void main(String[] args) { 
     SimpleElement se1 = new SimpleElement(10); 
     SimpleElement se2 = new SimpleElement(20); 
     SimpleElement se3 = new SimpleElement(30); 
     RootElement root = new RootElement(); 

     root.totalWeight.addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> { 
      System.out.println(newValue); 
     }); 

     root.addElement(se1); 
     root.addElement(se2); 
     root.addElement(se3); 

     se1.setWeight(1000); 
     root.removeElement(se3); 

    } 

} 

很遺憾,像監視列表中元素屬性總和這樣的常見任務需要難看的樣板。