Issue
I'm working on a JavaFX code which generates 4 different shapes (circle,rectangle,line,ellipse) each time the user presses the button , so far I've done the circle and the rectangle , the shapes are getting generated very well , but the problem is that when I press the button I can't move the shapes , even though it moved them very well before I added the button , I can't figure out what's wrong with the code.
Here is the CODE :
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);
}
}
Solution
The problem is that the button retains keyboard focus after you press it, and consumes the key events. One solution is to relinquish focus by passing it to, for example, the shape you create:
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();
}
}
}
If you specifically want the button to retain focus (so it responds to its usual key events, such as generating an action from SPACE, you can use a different key event. This seems a less robust solution though (relying on the internal event handling of the button):
pane.setOnKeyReleased(e -> {
// ...
});
Answered By - James_D
Answer Checked By - Mildred Charles (JavaFixing Admin)