JavaFX - 生成形状并用箭头移动它们
JavaFX - Generating shapes and moving them with arrows
我正在编写一个 JavaFX 代码,每次用户按下按钮时它都会生成 4 种不同的形状(圆形、矩形、直线、椭圆形),到目前为止我已经完成了圆形和矩形,形状是生成得很好,但问题是当我按下按钮时我无法移动形状,即使在我添加按钮之前它移动得很好,我也不知道代码有什么问题。
这是代码:
package sample;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import javafx.scene.control.Button;
import javafx.scene.shape.Rectangle;
import javafx.geometry.Insets;
import java.util.Random;
public class Main extends Application {
Pane pane;
Circle circle;
Rectangle rectangle;
@Override
public void start(Stage primaryStage) {
pane = new Pane();
Button button = new Button("Generate");
CreateRect c = new CreateRect();
button.setOnAction(c);
pane.setPadding(new Insets(30, 30, 30, 30));
circle = new Circle(30, 30, 30);
rectangle = new Rectangle(30,30,50,20);
pane.getChildren().add(button);
pane.setOnKeyPressed(e -> {
switch (e.getCode()) {
case UP : circle.setCenterY(circle.getCenterY() >
circle.getRadius() ? circle.getCenterY() - 15 :
circle.getCenterY()); break;
case DOWN : circle.setCenterY(circle.getCenterY() <
pane.getHeight() - circle.getRadius() ?
circle.getCenterY() + 15 : circle.getCenterY());
break;
case LEFT : circle.setCenterX(circle.getCenterX() >
circle.getRadius() ? circle.getCenterX() - 15 :
circle.getCenterX()); break;
case RIGHT : circle.setCenterX(circle.getCenterX() <
pane.getWidth() - circle.getRadius() ?
circle.getCenterX() + 15: circle.getCenterX());
}
});
Scene scene = new Scene(pane, 500, 300);
primaryStage.setTitle("SHAPES");
primaryStage.setScene(scene);
primaryStage.show();
pane.requestFocus();
}
private class CreateRect implements EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent e) {
double s;
Random generator = new Random();
s = generator.nextDouble();
pane.getChildren().remove(rectangle);
pane.getChildren().remove(circle);
if (s < 0.5) {
pane.getChildren().add(rectangle);
rectangle.setX(100);
rectangle.setY(100);
rectangle.setWidth(50);
rectangle.setHeight(20);
rectangle.setFill(Color.RED);
} else {
pane.getChildren().add(circle);
circle.setCenterX(100);
circle.setCenterY(100);
circle.setRadius(80);
circle.setFill(Color.RED);
}
}
}
public static void main(String[] args) {
launch(args);
}
}
你的代码
switch (e.getCode()) {
case UP : circle.setCenterY(circle.getCenterY() >
circle.getRadius() ? circle.getCenterY() - 15 :
circle.getCenterY()); break;
case DOWN : circle.setCenterY(circle.getCenterY() <
pane.getHeight() - circle.getRadius() ?
circle.getCenterY() + 15 : circle.getCenterY());
break;
case LEFT : circle.setCenterX(circle.getCenterX() >
circle.getRadius() ? circle.getCenterX() - 15 :
circle.getCenterX()); break;
case RIGHT : circle.setCenterX(circle.getCenterX() <
pane.getWidth() - circle.getRadius() ?
circle.getCenterX() + 15: circle.getCenterX());
}
仅适用于 circle
,因此您必须注意其他形状的代码
例如:
pane.setOnKeyPressed(e -> {
switch (e.getCode()) {
case UP : circle.setCenterY(circle.getCenterY() >
circle.getRadius() ? circle.getCenterY() - 15 :
circle.getCenterY());
break;
case DOWN : circle.setCenterY(circle.getCenterY() <
pane.getHeight() - circle.getRadius() ?
circle.getCenterY() + 15 : circle.getCenterY());
break;
case LEFT : circle.setCenterX(circle.getCenterX() >
circle.getRadius() ? circle.getCenterX() - 15 :
circle.getCenterX());
break;
case RIGHT : circle.setCenterX(circle.getCenterX() <
pane.getWidth() - circle.getRadius() ?
circle.getCenterX() + 15: circle.getCenterX());
break;
}
switch (e.getCode()) {
case UP : rectangle.setY(rectangle.getY()-15);
break;
case DOWN : rectangle.setY(rectangle.getY()+15);
break;
case LEFT : rectangle.setX(rectangle.getX()-15);
break;
case RIGHT : rectangle.setX(rectangle.getX()+15);
break;
}
});
(最好使用更多 OOP 方法)
问题是按钮在您按下后保留了键盘焦点,并消耗了按键事件。一种解决方案是通过将焦点传递给您创建的形状来放弃焦点:
private class CreateRect implements EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent e) {
double s;
Random generator = new Random();
s = generator.nextDouble();
pane.getChildren().remove(rectangle);
pane.getChildren().remove(circle);
if (s < 0.5) {
pane.getChildren().add(rectangle);
rectangle.setX(100);
rectangle.setY(100);
rectangle.setWidth(50);
rectangle.setHeight(20);
rectangle.setFill(Color.RED);
rectangle.requestFocus();
} else {
pane.getChildren().add(circle);
circle.setCenterX(100);
circle.setCenterY(100);
circle.setRadius(80);
circle.setFill(Color.RED);
circle.requestFocus();
}
}
}
如果您特别希望按钮保持焦点(以便它响应其通常的按键事件,例如从 SPACE 生成一个动作,您可以使用不同的关键事件。尽管这似乎是一个不太可靠的解决方案(依赖于按钮的内部事件处理):
pane.setOnKeyReleased(e -> {
// ...
});
如果您将事件处理程序视为调用操作的触发器,则更容易概念化。然后你可以更容易地分解事情。因此,我已将您的 EventHandler class 转换为一个简单的方法,并从 lambda 调用它,这也会将焦点重置回窗格:
public class Main extends Application {
Pane pane;
Circle circle;
Rectangle rectangle;
@Override
public void start(Stage primaryStage) {
pane = new Pane();
Button button = new Button("Generate");
button.setOnAction(evt -> {
createShape();
pane.requestFocus();
});
pane.setPadding(new Insets(30, 30, 30, 30));
circle = new Circle(30, 30, 30);
rectangle = new Rectangle(30, 30, 50, 20);
pane.getChildren().addAll(button, circle);
pane.setOnKeyPressed(e -> {
switch (e.getCode()) {
case UP:
circle.setCenterY(circle.getCenterY() >
circle.getRadius() ? circle.getCenterY() - 15 :
circle.getCenterY());
break;
case DOWN:
circle.setCenterY(circle.getCenterY() <
pane.getHeight() - circle.getRadius() ?
circle.getCenterY() + 15 : circle.getCenterY());
break;
case LEFT:
circle.setCenterX(circle.getCenterX() >
circle.getRadius() ? circle.getCenterX() - 15 :
circle.getCenterX());
break;
case RIGHT:
circle.setCenterX(circle.getCenterX() <
pane.getWidth() - circle.getRadius() ?
circle.getCenterX() + 15 : circle.getCenterX());
}
});
Scene scene = new Scene(pane, 500, 300);
primaryStage.setTitle("SHAPES");
primaryStage.setScene(scene);
primaryStage.show();
pane.requestFocus();
}
public void createShape() {
double s;
Random generator = new Random();
s = generator.nextDouble();
pane.getChildren().remove(rectangle);
pane.getChildren().remove(circle);
if (s < 0.5) {
pane.getChildren().add(rectangle);
rectangle.setX(100);
rectangle.setY(100);
rectangle.setWidth(50);
rectangle.setHeight(20);
rectangle.setFill(Color.RED);
} else {
pane.getChildren().add(circle);
circle.setCenterX(100);
circle.setCenterY(100);
circle.setRadius(80);
circle.setFill(Color.RED);
}
}
public static void main(String[] args) {
launch(args);
}
}
应该可以。不过,Sarel 关于具有形状特定运动的评论是完全正确的。我将使用 setTranslateX() 和 setTranslateY() 移动形状。
我正在编写一个 JavaFX 代码,每次用户按下按钮时它都会生成 4 种不同的形状(圆形、矩形、直线、椭圆形),到目前为止我已经完成了圆形和矩形,形状是生成得很好,但问题是当我按下按钮时我无法移动形状,即使在我添加按钮之前它移动得很好,我也不知道代码有什么问题。
这是代码:
package sample;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import javafx.scene.control.Button;
import javafx.scene.shape.Rectangle;
import javafx.geometry.Insets;
import java.util.Random;
public class Main extends Application {
Pane pane;
Circle circle;
Rectangle rectangle;
@Override
public void start(Stage primaryStage) {
pane = new Pane();
Button button = new Button("Generate");
CreateRect c = new CreateRect();
button.setOnAction(c);
pane.setPadding(new Insets(30, 30, 30, 30));
circle = new Circle(30, 30, 30);
rectangle = new Rectangle(30,30,50,20);
pane.getChildren().add(button);
pane.setOnKeyPressed(e -> {
switch (e.getCode()) {
case UP : circle.setCenterY(circle.getCenterY() >
circle.getRadius() ? circle.getCenterY() - 15 :
circle.getCenterY()); break;
case DOWN : circle.setCenterY(circle.getCenterY() <
pane.getHeight() - circle.getRadius() ?
circle.getCenterY() + 15 : circle.getCenterY());
break;
case LEFT : circle.setCenterX(circle.getCenterX() >
circle.getRadius() ? circle.getCenterX() - 15 :
circle.getCenterX()); break;
case RIGHT : circle.setCenterX(circle.getCenterX() <
pane.getWidth() - circle.getRadius() ?
circle.getCenterX() + 15: circle.getCenterX());
}
});
Scene scene = new Scene(pane, 500, 300);
primaryStage.setTitle("SHAPES");
primaryStage.setScene(scene);
primaryStage.show();
pane.requestFocus();
}
private class CreateRect implements EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent e) {
double s;
Random generator = new Random();
s = generator.nextDouble();
pane.getChildren().remove(rectangle);
pane.getChildren().remove(circle);
if (s < 0.5) {
pane.getChildren().add(rectangle);
rectangle.setX(100);
rectangle.setY(100);
rectangle.setWidth(50);
rectangle.setHeight(20);
rectangle.setFill(Color.RED);
} else {
pane.getChildren().add(circle);
circle.setCenterX(100);
circle.setCenterY(100);
circle.setRadius(80);
circle.setFill(Color.RED);
}
}
}
public static void main(String[] args) {
launch(args);
}
}
你的代码
switch (e.getCode()) {
case UP : circle.setCenterY(circle.getCenterY() >
circle.getRadius() ? circle.getCenterY() - 15 :
circle.getCenterY()); break;
case DOWN : circle.setCenterY(circle.getCenterY() <
pane.getHeight() - circle.getRadius() ?
circle.getCenterY() + 15 : circle.getCenterY());
break;
case LEFT : circle.setCenterX(circle.getCenterX() >
circle.getRadius() ? circle.getCenterX() - 15 :
circle.getCenterX()); break;
case RIGHT : circle.setCenterX(circle.getCenterX() <
pane.getWidth() - circle.getRadius() ?
circle.getCenterX() + 15: circle.getCenterX());
}
仅适用于 circle
,因此您必须注意其他形状的代码
例如:
pane.setOnKeyPressed(e -> {
switch (e.getCode()) {
case UP : circle.setCenterY(circle.getCenterY() >
circle.getRadius() ? circle.getCenterY() - 15 :
circle.getCenterY());
break;
case DOWN : circle.setCenterY(circle.getCenterY() <
pane.getHeight() - circle.getRadius() ?
circle.getCenterY() + 15 : circle.getCenterY());
break;
case LEFT : circle.setCenterX(circle.getCenterX() >
circle.getRadius() ? circle.getCenterX() - 15 :
circle.getCenterX());
break;
case RIGHT : circle.setCenterX(circle.getCenterX() <
pane.getWidth() - circle.getRadius() ?
circle.getCenterX() + 15: circle.getCenterX());
break;
}
switch (e.getCode()) {
case UP : rectangle.setY(rectangle.getY()-15);
break;
case DOWN : rectangle.setY(rectangle.getY()+15);
break;
case LEFT : rectangle.setX(rectangle.getX()-15);
break;
case RIGHT : rectangle.setX(rectangle.getX()+15);
break;
}
});
(最好使用更多 OOP 方法)
问题是按钮在您按下后保留了键盘焦点,并消耗了按键事件。一种解决方案是通过将焦点传递给您创建的形状来放弃焦点:
private class CreateRect implements EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent e) {
double s;
Random generator = new Random();
s = generator.nextDouble();
pane.getChildren().remove(rectangle);
pane.getChildren().remove(circle);
if (s < 0.5) {
pane.getChildren().add(rectangle);
rectangle.setX(100);
rectangle.setY(100);
rectangle.setWidth(50);
rectangle.setHeight(20);
rectangle.setFill(Color.RED);
rectangle.requestFocus();
} else {
pane.getChildren().add(circle);
circle.setCenterX(100);
circle.setCenterY(100);
circle.setRadius(80);
circle.setFill(Color.RED);
circle.requestFocus();
}
}
}
如果您特别希望按钮保持焦点(以便它响应其通常的按键事件,例如从 SPACE 生成一个动作,您可以使用不同的关键事件。尽管这似乎是一个不太可靠的解决方案(依赖于按钮的内部事件处理):
pane.setOnKeyReleased(e -> {
// ...
});
如果您将事件处理程序视为调用操作的触发器,则更容易概念化。然后你可以更容易地分解事情。因此,我已将您的 EventHandler class 转换为一个简单的方法,并从 lambda 调用它,这也会将焦点重置回窗格:
public class Main extends Application {
Pane pane;
Circle circle;
Rectangle rectangle;
@Override
public void start(Stage primaryStage) {
pane = new Pane();
Button button = new Button("Generate");
button.setOnAction(evt -> {
createShape();
pane.requestFocus();
});
pane.setPadding(new Insets(30, 30, 30, 30));
circle = new Circle(30, 30, 30);
rectangle = new Rectangle(30, 30, 50, 20);
pane.getChildren().addAll(button, circle);
pane.setOnKeyPressed(e -> {
switch (e.getCode()) {
case UP:
circle.setCenterY(circle.getCenterY() >
circle.getRadius() ? circle.getCenterY() - 15 :
circle.getCenterY());
break;
case DOWN:
circle.setCenterY(circle.getCenterY() <
pane.getHeight() - circle.getRadius() ?
circle.getCenterY() + 15 : circle.getCenterY());
break;
case LEFT:
circle.setCenterX(circle.getCenterX() >
circle.getRadius() ? circle.getCenterX() - 15 :
circle.getCenterX());
break;
case RIGHT:
circle.setCenterX(circle.getCenterX() <
pane.getWidth() - circle.getRadius() ?
circle.getCenterX() + 15 : circle.getCenterX());
}
});
Scene scene = new Scene(pane, 500, 300);
primaryStage.setTitle("SHAPES");
primaryStage.setScene(scene);
primaryStage.show();
pane.requestFocus();
}
public void createShape() {
double s;
Random generator = new Random();
s = generator.nextDouble();
pane.getChildren().remove(rectangle);
pane.getChildren().remove(circle);
if (s < 0.5) {
pane.getChildren().add(rectangle);
rectangle.setX(100);
rectangle.setY(100);
rectangle.setWidth(50);
rectangle.setHeight(20);
rectangle.setFill(Color.RED);
} else {
pane.getChildren().add(circle);
circle.setCenterX(100);
circle.setCenterY(100);
circle.setRadius(80);
circle.setFill(Color.RED);
}
}
public static void main(String[] args) {
launch(args);
}
}
应该可以。不过,Sarel 关于具有形状特定运动的评论是完全正确的。我将使用 setTranslateX() 和 setTranslateY() 移动形状。