JavaFX Canvas вращает изображение с фиксированным центром (и без отскока)

Я пытался запрограммировать мельницу с вращающимся ротором / головкой. Сам ствол фиксируется и рисуется в качестве фона на холсте (javafx). Сам ротор / головка - другое изображение. Я думал, что смогу повернуть само изображение и нарисовать его на графическом тексте. (Не сработало) Потом я попробовал разные вещи:

а. Рисуя изображение на другом холсте, вращайте холст, сделайте снимок этого холста. (Не работает)

б. Сделайте просмотр изображений, поверните просмотр изображений, сделайте снимок и нарисуйте его (не работает) и

с. Я пытался сделать RotateTransition (не работает). Теперь я вернулся к b: ImageView изображения, которое я вращаю.

б работы вроде, вроде! Это как-то "подпрыгивает", и я не знаю почему, потому что док говорит, что ImageView.setRotate (..) вращает изображение вокруг центра. Само изображение имеет одинаковую высоту и длину, поэтому оно должно подпрыгивать, как если бы это был прямоугольник. Я просто хочу, чтобы этот отскок прекратился... см. Здесь (ТАК не позволил мне опубликовать gif)

Все эти неудачные попытки пришли из чтения этого форума.

Исходный код здесь или в виде текста:

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.setRotate(). Моя проблема (для которой я разместил эту тему) возникла из-за использования холста. Я до сих пор не знаю, как возникла прыгающая ошибка, но цель моего проекта достигнута. Новый исходный код в ответах.

1 ответ

Я имел в виду размещать узлы в графе сцены вместо рисования на холсте. Конечно, вы (конечно) размещаете холст в графе сцены. Но по своей сути сложно изменить холст после его рисования. - @James_D

Этот комментарий помог и решил мою проблему. Новый исходный код указан в вопросе. Вместо того, чтобы рисовать его на холсте, я поместил все объекты в граф сцены и переместил изображение вместо холста или изображения. Вот новый исходный код:

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);
            }
        };
    }
}
Другие вопросы по тегам