2013-06-04 4 views
2

У меня есть класс SimpleElement, который имеет поле веса, а второй имеет список SimpleElement и поле веса, которое зависит от суммы веса всех остальных простых элементов, содержащихся в списке. Кто-нибудь знает, как это сделать, привязывая?
Мой код: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

Рассмотрите [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 использует Fluent API для построения цепочки привязок, я считаю, что трудно чистить и поддерживать, когда объекты могут быть удалены или заменены. Лучше использовать API низкого уровня.

Несмотря на огромный набор готовых связующих материалов в API JavaFX, 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); 

    } 

} 

Это печально, что такая общая задача, как контроль суммы свойств элемента в списке требует что уродливых шаблонной.

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