Overlay with AnchorLayout

Aim of this post is to show how multiple animations or other nodes can be placed side by side in an efficient way on a single layer on the stack

The basic example is still the same as in the last post. However this time the ImageView is put into an AnchorPane which is added on the stack.

package javafxtest;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
 *
 * @author andi
 */
public class OverlayLayoutTest extends Application {

    private Timeline timeLine;
    private List images;
    private Random rnd = new Random(System.nanoTime());
    //private ImageView animation = null;
    private AnchorPane animationPane = null;

    @Override
    public void start(Stage stage) throws FileNotFoundException {
        final StackPane root = new StackPane();
        File f = new File("/home/andi/Pictures/Adam.jpg");
        Image image = new Image(new FileInputStream(f));
        final double width = image.getWidth();
        final double height = image.getHeight();
        Canvas background = new Canvas(width, height);
        GraphicsContext context = background.getGraphicsContext2D();
        context.drawImage(image, 0, 0);

        root.getChildren().add(background);

        images = new ArrayList<>();
        images.add(new Image(new FileInputStream(new File("/home/andi/Pictures/kajak1.png"))));
        images.add(new Image(new FileInputStream(new File("/home/andi/Pictures/kajak2.png"))));
        images.add(new Image(new FileInputStream(new File("/home/andi/Pictures/kajak3.png"))));
        images.add(new Image(new FileInputStream(new File("/home/andi/Pictures/kajak4.png"))));
        images.add(new Image(new FileInputStream(new File("/home/andi/Pictures/kajak5.png"))));

        final int xRange = (int) (width - images.get(0).getWidth());
        final int yRange = (int) (height - images.get(0).getHeight());

       // final Canvas animation = new Canvas(width, height);
        //final GraphicsContext context2 = animation.getGraphicsContext2D();

        timeLine = new Timeline();
        timeLine.setCycleCount(Timeline.INDEFINITE);
        timeLine.getKeyFrames().add(
                new KeyFrame(Duration.millis(500), 
                    new EventHandler() {

                        @Override
                        public void handle(ActionEvent t) {
                            final int nextIndex = rnd.nextInt(images.size());
                            Image kajak = images.get(nextIndex);
                            final AnchorPane previous = animationPane;
                            ImageView animation = new ImageView(kajak);
                            System.out.println("Draw image with index "+nextIndex);
                            int rndX = rnd.nextInt(xRange);
                            int rndY = rnd.nextInt(yRange);
                            animationPane = new AnchorPane();
                            AnchorPane.setTopAnchor(animation, (double) rndY);
                            AnchorPane.setLeftAnchor(animation, (double) rndX);
                            AnchorPane.setBottomAnchor(animation, 0.0);
                            AnchorPane.setRightAnchor(animation, 0.0);
                            animationPane.getChildren().add(animation);
                            root.getChildren().remove(previous);
                            root.getChildren().add(animationPane);
                        }
                    }, 
                    new KeyValue[0]) // don't use binding
        );
        timeLine.playFromStart();

        Scene scene = new Scene(root, width, height);

        stage.setTitle("Moving ImageView Overlay Test");
        stage.setScene(scene);
        stage.show();
    }

    /**
     * The main() method is ignored in correctly deployed JavaFX application.
     * main() serves only as fallback in case the application can not be
     * launched through deployment artifacts, e.g., in IDEs with limited FX
     * support. NetBeans ignores main().
     *
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}

In the end each node in the overlay will be such an AnchorPane in a second stack layout on the root stack. I will do it so complicatedly so it is easier to use. I want to be able to add animations and nodes to the overlay (back to front). When creating a custom Layout using these existing layouts, I will be able to provide simple setter methods.

An extension of the anchor pane will then be an animated pane. Imagine a walk cycle of o figure. Each image in the animation has a different location, while the difference in the location stays constant. This will hold for all animations, so I only have to pass the direction of the walk.

The animation is added to all four available anchor points. This should result in proper scaling. This will be the next issue:

  • Scaling of a box
  • Scaling of an image

 

Schreibe einen Kommentar