lundi 16 septembre 2013

Lambda and JavaFX 8.0

Updating my Mac with:
Now, let's try to play with Lambda …  and JavaFX 8.0

My first try is a classical replace of the ActionEvent of a button by a Lambda and a less classical call of an existing method by using method references.
And my second try is to rewrite Duke Anim with Lambda.

Button action with Lambda and method references
/ButtonJavaFX8Lambda.java
package buttonjavafx8lambda;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class ButtonJavaFX8Lambda extends Application {
    
    public void test(ActionEvent e){
        System.out.println("Hello World method references");
    }
   
    public static void testStatic(ActionEvent e){
        System.out.println("Hello World method references static");
    }
    
    @Override
    public void start(Stage primaryStage) {
        Button btn = new Button();
        Button btn2 = new Button();
        
        btn.setText("Say 'Hello World Lambda'");
        btn2.setText("Say 'Hello World method references'");
        
        // Lambda
        btn.setOnAction(e->{
            System.out.println("Hello World Lambda");
        });
        
        // method references 
        btn2.setOnAction(this::test);
        //// method references (static method)
        //btn2.setOnAction(ButtonJavaFX8Lambda::testStatic);
        
        VBox root = new VBox();
        root.setSpacing(10);
        root.setPadding(new Insets(50, 30, 50, 30));
        root.getChildren().add(btn);
        root.getChildren().add(btn2);
        
        Scene scene = new Scene(root, 300, 250);
        
        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }  
}
Rewriting Duke Anim with Lambda
Builders are deprecated in JavaFX 8.0, so I began to rewrite Duke Anim without the builders.
DukeAnimJavaFX8.java
package dukeanimjavafx8;

import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import javafx.util.Duration;

public class DukeAnimJavaFX8 extends Application {
    
    @Override
    public void start(Stage primaryStage) {
        DukeAnimModel dukeAnimModel  = new DukeAnimModel();
        dukeAnimModel.initTimeline();
        dukeAnimModel.timeline.play();
        
        primaryStage.setTitle("DukeAnim JavaFX 8(b99)");
        
        Image image = new Image(DukeAnimJavaFX8.class.getResourceAsStream("images/duke.png"));
        
        ImageView imageView = new ImageView();
        imageView.setImage(image);
        
        Group root = new Group();
        root.getChildren().add(imageView);
        
        Scene scene = new Scene(root,240,320);

        imageView.xProperty().bind(dukeAnimModel.x);
        imageView.yProperty().bind(dukeAnimModel.y); 
                
        primaryStage.setScene(scene);                
        primaryStage.show();       
    }

    public static void main(String[] args) {
        launch(args);
    }
    
}

class DukeAnimModel {

    private EventHandler action = new EventHandler<ActionEvent>() {

        public void handle(ActionEvent t) {
            System.out.println("x : " + x);
            System.out.println("y : " + y);

            int xTarget = (new Double(java.lang.Math.random() * 240 + 1)).intValue();
            int yTarget = (new Double(java.lang.Math.random() * 320 + 1)).intValue();

            System.out.println("xTarget : " + xTarget);
            System.out.println("xTarget : " + yTarget);

            KeyFrame kf1s = buildKeyFrame(xTarget, yTarget);

            timeline.stop();
            timeline.getKeyFrames().remove(0);
            timeline.getKeyFrames().add(kf1s);
            timeline.play();

        }
    };

    private KeyFrame buildKeyFrame(int xTarget, int yTarget) {

        Duration t1 = new Duration(1000);
        KeyValue kvx1s = new KeyValue(x, xTarget, Interpolator.SPLINE(0, 0.5, 0.5, 1));
        KeyValue kvy1s = new KeyValue(y, yTarget, Interpolator.SPLINE(0, 0.5, 0.5, 1));
        KeyFrame kf1s = new KeyFrame(t1, action, kvx1s, kvy1s);

        return kf1s;
    }
    
    public IntegerProperty x = new SimpleIntegerProperty(0);
    public IntegerProperty y = new SimpleIntegerProperty(0); 
    
    public Timeline timeline = new Timeline();
    
    public void initTimeline(){
        timeline.setAutoReverse(true);
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.getKeyFrames().add(buildKeyFrame(0,0));
    }     
}


Then I replace the ActionEvent of the KeyFrame by a Lambda
DukeAnimModel

class DukeAnimModel {

    private KeyFrame buildKeyFrame(int xTarget, int yTarget) {

        Duration t1 = new Duration(1000);
        KeyValue kvx1s = new KeyValue(x, xTarget, Interpolator.SPLINE(0, 0.5, 0.5, 1));
        KeyValue kvy1s = new KeyValue(y, yTarget, Interpolator.SPLINE(0, 0.5, 0.5, 1));
                KeyFrame kf1s = new KeyFrame(t1,
                a -> {
                           System.out.println("x : " + x);
                           System.out.println("y : " + y);

                            int xTarget1 = (new Double(java.lang.Math.random() * 240 + 1)).intValue();
                            int yTarget1 = (new Double(java.lang.Math.random() * 320 + 1)).intValue();

                            System.out.println("xTarget : " + xTarget1);
                            System.out.println("xTarget : " + yTarget1);

                            timeline.stop();
                            timeline.getKeyFrames().remove(0);
                            timeline.getKeyFrames().add(buildKeyFrame(xTarget1, yTarget1));
                            timeline.play();
                }, 
                kvx1s, kvy1s);
        return kf1s;
    }
    
    public IntegerProperty x = new SimpleIntegerProperty(0);
    public IntegerProperty y = new SimpleIntegerProperty(0); 
    
    public Timeline timeline = new Timeline();
    
    public void initTimeline(){
        timeline.setAutoReverse(true);
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.getKeyFrames().add(buildKeyFrame(0,0));
    }     
}

And I finish by rewrite the buildKeyFrame method as a Lambda, by using the BiFunction interface which allows to create a Lambda with 2 inputs parameters.
To execute the Lambda, just call the method apply with 2 parameters.
Ok, in this case, write this code with a Lambda brings nothing... it's just to try ;) and to show how write a Lambda and execute a Lambda.
DukeAnimJavaFX8Lambda.java
package dukeanimjavafx8lambda;

import java.util.function.BiFunction;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import javafx.util.Duration;

public class DukeAnimJavaFX8Lambda extends Application {
    
    public IntegerProperty x = new SimpleIntegerProperty(0);
    public IntegerProperty y = new SimpleIntegerProperty(0); 
    
    public Timeline timeline = new Timeline();
    
    BiFunction<Integer,Integer,KeyFrame> buildKeyFrame = (Integer xTarget, Integer yTarget) -> {
                
        Duration t1 = new Duration(1000);
        KeyValue kvx1s = new KeyValue(x, xTarget, Interpolator.SPLINE(0, 0.5, 0.5, 1));
        KeyValue kvy1s = new KeyValue(y, yTarget, Interpolator.SPLINE(0, 0.5, 0.5, 1));
        KeyFrame kf1s = new KeyFrame(t1,
                a -> {
                           System.out.println("x : " + x);
                           System.out.println("y : " + y);

                            int xTarget1 = (new Double(java.lang.Math.random() * 240 + 1)).intValue();
                            int yTarget1 = (new Double(java.lang.Math.random() * 320 + 1)).intValue();

                            System.out.println("xTarget : " + xTarget1);
                            System.out.println("xTarget : " + yTarget1);

                            timeline.stop();
                            timeline.getKeyFrames().remove(0);
                            timeline.getKeyFrames().add(buildKeyFrame.apply(xTarget1, yTarget1));
                            timeline.play();
                }, 
                kvx1s, kvy1s);

        return kf1s;   
    };
    
    @Override
    public void start(Stage primaryStage) {
         
        timeline.setAutoReverse(true);
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.getKeyFrames().add(buildKeyFrame.apply(0,0));
        timeline.play();
        
        primaryStage.setTitle("DukeAnim JavaFX 8(b99)");
        
        Image image = new Image(DukeAnimJavaFX8Lambda.class.getResourceAsStream("images/duke.png"));
        
        ImageView imageView = new ImageView();
        imageView.setImage(image);
        
        Group root = new Group();
        root.getChildren().add(imageView);
        
        Scene scene = new Scene(root,240,320);
        
        imageView.xProperty().bind(x);
        imageView.yProperty().bind(y); 
        
        primaryStage.setScene(scene);                
        primaryStage.show();       
    }

    public static void main(String[] args) {
        launch(args);
    }    
}


Aucun commentaire: