我有一个类SimpleElement
,它有一个权重字段,第二个有一个SimpleElement
列表和一个权重字段,它取决于所有其他SimpleElement
s的权重之和包含在列表中。任何人都知道怎么做绑定?
我的代码:
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 :(得分: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);
}
执行上面的代码会产生:
3
5
6
答案 1 :(得分:1)
Crferreira的答案使用Fluent 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);
}
}
令人遗憾的是,监视列表中元素属性总和这样的常见任务需要这个丑陋的样板。
答案 2 :(得分:1)
仅获取总和并将属性绑定到总和。因此,对总和的任何更改都将通过绑定属性来观察