JavaFX - bind property to properties of every element in observable Collection


Question

Does exist any method which bind BooleanProperty to conjunction of every element in ObservableList?

ObservableList<BooleanProperty> list;
list = FXCollections.observableList(new ArrayList<BooleanProperty>));
BooleanProperty emptyProperty = new SimpleBooleanProperty();
emptyProperty.bind(Bindings.conunction(list));`

Is there such a method as:

static BooleanBinding conjunction(ObservableList<BooleanProperty> op)
1
7
12/7/2012 1:52:09 PM

Accepted Answer

There is no conjunction api defined in the JavaFX 2.2 platform.

You could create a ConjunctionBooleanBinding (aka AllTrueBinding) by subclassing BooleanBinding.

Accept the ObservableList in the constructor of your new class, and use the low level binding api in an overridden computeValue method to set the binding value based upon logically anding together all of the boolean values in the list.

Here is a sample implementation. The sample could be further performance optimized and make use of WeakReferences, so it does not require manual disposition.

import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.collections.*;

public class AllTrueBinding extends BooleanBinding {
  private final ObservableList<BooleanProperty> boundList;
  private final ListChangeListener<BooleanProperty> BOUND_LIST_CHANGE_LISTENER =
    new ListChangeListener<BooleanProperty>() {
      @Override public void onChanged(
             ListChangeListener.Change<? extends BooleanProperty> change
          ) {
        refreshBinding();
      }
    };
  private BooleanProperty[] observedProperties = {};

  AllTrueBinding(ObservableList<BooleanProperty> booleanList) {
    booleanList.addListener(BOUND_LIST_CHANGE_LISTENER);
    boundList = booleanList;
    refreshBinding();
  }

  @Override protected boolean computeValue() {
    for (BooleanProperty bp: observedProperties) {
      if (!bp.get()) {
        return false;
      }
    }

    return true;
  }

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

  private void refreshBinding() {
    super.unbind(observedProperties);
    observedProperties = boundList.toArray(new BooleanProperty[0]);
    super.bind(observedProperties);
    this.invalidate();
  }
}

And here is a test harness to demonstrate how it works:

import java.util.*;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class ListBindingTest {
  final BooleanProperty a = new SimpleBooleanProperty(true);
  final BooleanProperty b = new SimpleBooleanProperty(true);
  final BooleanProperty c = new SimpleBooleanProperty(true);
  final BooleanProperty d = new SimpleBooleanProperty(true);
  final ObservableList<BooleanProperty> booleanList =
    FXCollections.observableArrayList(a, b, c, d);

  public static void main(String[] args) {
    new ListBindingTest().test();
  }

  private void test() {
    AllTrueBinding at = new AllTrueBinding(booleanList);

    System.out.println(at.get() + forArrayString(booleanList));

    b.set(false);
    System.out.println(at.get() + forArrayString(booleanList));

    b.set(true);
    System.out.println(at.get() + forArrayString(booleanList));

    booleanList.add(new SimpleBooleanProperty(false));
    System.out.println(at.get() + forArrayString(booleanList));

    booleanList.remove(3, 5);
    System.out.println(at.get() + forArrayString(booleanList));

    at.dispose();
  }  

  private String forArrayString(List list) {
    return " for " + Arrays.toString(list.toArray());
  }
}
5
12/8/2012 1:03:33 AM

You can easily implement the method as follows:

public static BooleanBinding conjunction(ObservableList<BooleanProperty> list){   
  BooleanBinding and = new SimpleBooleanProperty(true).and(list.get(0));
  for(int i = 1; i < list.size(); i++){
    and = and.and(list.get(i));   
  }
  return and;
}

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon