This discussion is archived
2 Replies Latest reply: Sep 6, 2013 2:39 PM by cayhorstmann RSS

Simpler Bound Properties with Lambdas

cayhorstmann Newbie
Currently Being Moderated

As I am climbing the learning curve, I find myself writing code such as

      more.disableProperty().bind(model.temperatureProperty()
         .greaterThanOrEqualTo(100));
      gauge.widthProperty().bind(model.temperatureProperty()
         .multiply(4));

I can see why one needs to build up these expression trees with methods such as greaterThanOrEqualTo and multiply, but it seems a bit tedious. So, I thought, why not let lambdas to the work? Feed the properties and a lambda that says how they should be evaluated when they change. Like this:

      more.disableProperty().bind(observe(model.temperatureProperty(),
            t -> t >= 100));
      gauge.widthProperty().bind(observe(model.temperatureProperty(),
            t -> 4 * t));

Maybe it's just me, but I find it easier on the eyes. The implementation of observe is trivial:

   static class Binding1<T, R> extends ObservableValueBase {
      private ObservableValue<T> obs;
      private Function<T, R> fun;
      
      public Binding1(ObservableValue<T> obs, Function<T, R> fun) {
         this.obs = obs;
         this.fun = fun;
         obs.addListener(o -> fireValueChangedEvent());         
      }

      public R getValue() {
         return fun.apply(obs.getValue());
      }
   }

   public static <T, R> ObservableValue<R> observe(ObservableValue<T> obs, Function<T, R> fun) {
      return new Binding1<T, R>(obs, fun);
   }

One would need a couple more of these functions to handle lambdas with 2 and maybe 3 and 4 parameters.

With this approach, there is no actual need to use things such as DoubleProperty because you can just do the evaluations in the lambda and don't need a bunch of methods to replicate the arithmetic operations.

Has anyone ever thought along these lines, or am I breaking new ground here? Or am I overlooking something that would doom this approach?

  • 1. Re: Simpler Bound Properties with Lambdas
    James_D Guru
    Currently Being Moderated

    The Bindings class has a whole slew of useful methods for creating bindings, including createObjectBinding(...), which I think does more or less what you're looking for here:

     

    import javafx.beans.binding.Bindings;
    import javafx.beans.property.BooleanProperty;
    import javafx.beans.property.DoubleProperty;
    import javafx.beans.property.SimpleBooleanProperty;
    import javafx.beans.property.SimpleDoubleProperty;
    public class BindingsWithLambdaTest {
      public static void main(String[] args) {
        final DoubleProperty temp = new SimpleDoubleProperty();
        final BooleanProperty more = new SimpleBooleanProperty();
        final DoubleProperty gauge = new SimpleDoubleProperty();
        
        more.bind(Bindings.createObjectBinding(
            () -> temp.doubleValue() >= 100, 
            temp)
        );
        gauge.bind(Bindings.createObjectBinding(
            () -> 4*temp.doubleValue(), 
            temp)
        ); 
        
        more.addListener(
            (observable, oldValue, newValue) -> System.out.printf("more changed from %s to %s%n", oldValue, newValue)
        );
        gauge.addListener(
            (observable, oldValue, newValue) -> System.out.printf("gauge changed from %.1f to %.1f%n", oldValue.doubleValue(), newValue.doubleValue())
        );
        
        temp.set(10);
        temp.set(40);
        temp.set(110);
      }
    }

     

    Message was edited by: James_D (added code sample)

  • 2. Re: Simpler Bound Properties with Lambdas
    cayhorstmann Newbie
    Currently Being Moderated

    Yes, that's similar to what I had in mind. It's not quite as good because one has to manually get the property values instead of having them passed to the lambda.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points