2

我有一个类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);
    }
}
4

3 回答 3

2

RootElement可以重写该类以创建对 each 的绑定,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

于 2013-08-02T14:46:55.423 回答
1

Crferreira 的答案使用 Fluent API 来构建绑定链,我发现当可以删除或替换对象时很难清理和维护。最好使用 Low-Level API。

尽管 JavaFX API 中有大量预构建的绑定内容,但 ListBinding 在其中一个元素获得新属性值时不会失效。所以你必须创建你的 IntegerBinding 子类,它监听列表中的变化并重新绑定到新属性本身。

基于来自类似答案的代码。

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);

    }

}

可悲的是,监视列表中元素属性的总和这样的常见任务需要丑陋的样板。

于 2014-06-18T02:11:17.717 回答
1

只需获取总和并将属性绑定到总和。因此,绑定属性将观察到对总和所做的任何更改

于 2020-02-14T05:38:40.617 回答