JavaFX Canvas 以固定中心旋转图像(并且没有弹跳)
JavaFX Canvas rotate image with fixed center (and without bouncing)
我尝试用旋转 rotor/head 编写风车程序。词干本身是固定的,并作为背景绘制到 canvas (javafx) 上。 rotor/head 本身是另一个图像。我以为我可以旋转图像本身并将其绘制到图形上下文中。 (没用)然后我尝试了各种方法:
一个。将图像绘制到另一个 canvas 上,旋转 canvas,拍摄那个 canvas 的快照。 (没用)
b。制作一个图像视图,旋转图像视图,对其进行快照并绘制它(无效)和
c。我试图制作一个 RotateTransition(没有用)。现在我回到 b: 我旋转的图像的 ImageView。
b 类作品,类!它以某种方式 "bounces" 我不知道为什么,因为文档说 ImageView.setRotate(..) 围绕中心旋转图像。图像本身具有相同的高度和长度,因此它应该像矩形一样弹跳。我只想停止弹跳。see here (SO didnt allow me to post a gif)
这些失败的尝试都来自于本论坛的阅读。
Source Code here 或文本:
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 帮了我大忙。我没有将它绘制到 canvas 上,而是将所有对象放在场景图中并将其移动到那里。由于我的 rotor/head 是图像视图,因此我能够使用 imageview.setRotate()。我的问题(为此我发布了此线程)源于对 canvas 的使用。我仍然不知道弹跳错误是如何发生的,但我的项目目标已经实现。新的源代码在答案中。
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
这条评论帮助并解决了我的问题。问题中列出了新的源代码。我没有将它绘制到 canvas 上,而是将所有对象放在场景图中并移动图像视图而不是 canvas 或图像。这是新的源代码:
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);
}
};
}
}
我尝试用旋转 rotor/head 编写风车程序。词干本身是固定的,并作为背景绘制到 canvas (javafx) 上。 rotor/head 本身是另一个图像。我以为我可以旋转图像本身并将其绘制到图形上下文中。 (没用)然后我尝试了各种方法:
一个。将图像绘制到另一个 canvas 上,旋转 canvas,拍摄那个 canvas 的快照。 (没用)
b。制作一个图像视图,旋转图像视图,对其进行快照并绘制它(无效)和
c。我试图制作一个 RotateTransition(没有用)。现在我回到 b: 我旋转的图像的 ImageView。
b 类作品,类!它以某种方式 "bounces" 我不知道为什么,因为文档说 ImageView.setRotate(..) 围绕中心旋转图像。图像本身具有相同的高度和长度,因此它应该像矩形一样弹跳。我只想停止弹跳。see here (SO didnt allow me to post a gif)
这些失败的尝试都来自于本论坛的阅读。
Source Code here 或文本:
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 帮了我大忙。我没有将它绘制到 canvas 上,而是将所有对象放在场景图中并将其移动到那里。由于我的 rotor/head 是图像视图,因此我能够使用 imageview.setRotate()。我的问题(为此我发布了此线程)源于对 canvas 的使用。我仍然不知道弹跳错误是如何发生的,但我的项目目标已经实现。新的源代码在答案中。
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
这条评论帮助并解决了我的问题。问题中列出了新的源代码。我没有将它绘制到 canvas 上,而是将所有对象放在场景图中并移动图像视图而不是 canvas 或图像。这是新的源代码:
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);
}
};
}
}