2 Replies Latest reply: Sep 6, 2013 4:39 PM by cayhorstmann RSS

    Simpler Bound Properties with Lambdas

    cayhorstmann

      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

          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

            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.