JavaFX Canvas以固定中心旋转图像(并且没有弹跳)

JavaFX Canvas以固定中心旋转图像(并且没有弹跳)

问题描述:

我试着用旋转的转子/头编程风车。茎本身是固定的,并作为背景绘制在画布上(javafx)。转子/头本身是另一个图像。我以为我可以自己旋转图像并将其绘制到graphicscontext上。 (没有用)然后我尝试了各种各样的东西:

I tried to programm a windmill with rotating rotor/head. The stem itself is fixed and drawn as a background onto a canvas (javafx). The rotor/head itself is another image. I thought I could rotate the image itself and draw it onto the graphicscontext. (Didn't work) Then I tried various things:

a。将图像绘制到另一个画布上,旋转画布,制作该画布的快照。 (没有用)

a. Drawing the image onto another canvas, rotate the canvas, make a snapshot of that canvas. (Didn't work)

b。制作一个imageview,旋转imageview,快照并绘制它(没有工作)和

b. Make an imageview, rotate the imageview, snapshot it and draw it (Didn't work) and

c。我试图制作一个RotateTransition(没有用)。现在我回到b:我旋转的图像的ImageView。

c. I tried to make a RotateTransition (Didn't work). Now I am back to b: an ImageView of the image which I rotate.

b有点作品,有点像!它以某种方式反弹,我不知道为什么,因为doc说ImageView.setRotate(..)围绕中心旋转图像。图像本身具有相同的高度和长度,因此它应该像一个矩形一样反弹。我只是希望这个反弹停止.. 看到这里(SO不允许我发布一个gif)

b sort of works, sort of! It somehow "bounces" and I don`t know why because the doc says that ImageView.setRotate(..) rotates the image around the center. The image itself has same height and length therefore it should bounce as if it were a rectangle.. I just want this bounce to stop.. see here (SO didnt allow me to post a gif)

所有这些失败的尝试都来自这个论坛的读物。

All of these failed tries came from readings of this forum.

源代码或作为文本:

package sample;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.io.IOException;


public class Main extends Application {
    private Pane root;
    private Canvas canvas;
    private GraphicsContext gc;
    SnapshotParameters params = new SnapshotParameters();

    private final Image stem = new Image(getClass().getResource("windrad.png").toExternalForm());
    private final ImageView wheel = new ImageView(new Image(getClass().getResource("rad.png").toExternalForm()));

    private final int height = 720;
    private final int width = 720;
    private final double distanceWidth = 400.0 / 720.0;
    private final double distanceHeight = 240.0 / 720.0;
    private int degrees = 0;

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

    @Override
    public void start(Stage primaryStage) throws Exception{
        params.setFill(Color.TRANSPARENT);

        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setLocation(getClass().getResource("sample.fxml"));

        try {
            root = fxmlLoader.load();
            canvas = (Canvas) fxmlLoader.getNamespace().get("canvas");
            canvas.setHeight(height);
            canvas.setWidth(width);
            primaryStage.setHeight(height);
            primaryStage.setWidth(width);
            gc = canvas.getGraphicsContext2D();
        } catch (IOException e) {
            e.printStackTrace();
        }

        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root));
        primaryStage.show();

        animation().start();
    }

    private AnimationTimer animation() {
        return new AnimationTimer() {
            @Override
            public void handle(long now) {
                gc.clearRect(0,0, width, height);
                gc.drawImage(stem, 0, 0);
                degrees = degrees >= 360 ? 0 : ++degrees;
                wheel.setRotate(degrees);
                gc.drawImage(wheel.snapshot(params, null),  width * distanceWidth - (int) wheel.getImage().getWidth() / 2, height * distanceHeight - (int) wheel.getImage().getHeight() / 2);

            }
        };
    }
}

好的,所以我搞定了! @James_D给了我很多帮助。我没有将它绘制到画布上,而是将所有对象放在场景图中并将其移动到那里。由于我的转子/头是imageview,我能够使用imageview.setRotate()。我的问题(我发布了这个帖子)是由画布的使用引起的。我仍然不知道弹跳的错误是如何发生的,但我的项目目标已实现。新的源代码在答案中。

Ok, so I got it working! @James_D helped me a lot. Instead of drawing it onto a canvas I placed all objects in a scenegraph and moved it there. Since my rotor/head is a imageview I was able to use imageview.setRotate(). My issue (for which I posted this thread) originated by the use of the canvas. I still don`t know how the bouncing bug occured but my project aim is achieved. The new source code is in the answers.


我的意思是在场景图中放置节点在画布上绘图当然,您(当然)将画布放在场景图中。但是一旦绘制出来,修改画布本身就很困难。 - @James_D

I meant place nodes in the scene graph instead of drawing on a canvas. Sure, you are (of course) placing the canvas in a scene graph. But it is inherently difficult to modify a canvas once drawn. - @James_D

此评论有助于解决我的问题。新的源代码列在问题中。我没有将它绘制到画布上,而是将所有对象放在场景图中并移动了一个imageview而不是画布或图像。下面是新的源代码:

This comment helped and solved my problem. The new source code is listed in the question. Instead of drawing it onto a canvas I put all objects in a scene graph and moved an imageview instead of a canvas or image. Heres the new source code:

package sample;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;

public class Main extends Application {
    private Group root;

    private final ImageView stem = new ImageView(new Image(getClass().getResource("windrad.png").toExternalForm()));
    private final ImageView wheel = new ImageView(new Image(getClass().getResource("rad.png").toExternalForm()));

    private final int height = 720;
    private final int width = 720;
    private final double distanceWidth = 360.0 / 720.0;
    private final double distanceHeight = 270.0 / 720.0;

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

    @Override
    public void start(Stage primaryStage) throws Exception{
        root = new Group();
        root.getChildren().add(stem);
        root.getChildren().add(wheel);
        wheel.setX(width * distanceWidth - wheel.getImage().getWidth() / 2);
        wheel.setY(height * distanceHeight - wheel.getImage().getHeight() / 2);
        primaryStage.setTitle("Pinwheel");
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
        primaryStage.getIcons().add(new Image(getClass().getResource("windrad.png").toExternalForm()));

        animation().start();
    }

    private AnimationTimer animation() {
        return new AnimationTimer() {
            @Override
            public void handle(long now) {
                wheel.setRotate(wheel.getRotate() + 1);
            }
        };
    }
}