Search code examples
javajavafxevent-handlingrootshapes

Click Event Handler: How to change shape type on click


I'm trying to create some Event Handlers that will change the shape I have on-screen when clicked. I have a defaulted rectangle already on the screen when I hit run. When clicked, the Square turns into a Circle. I have another event handler that will do the reverse, Circle to Square. The problem I'm having is since the circle-shaped isn't created until after the Event Handler takes place, the compiler is giving the error: "Error: cannot find symbol" -> cir (The name I've given for the circle.)

I feel I'm going down the wrong path for a simple problem. Is there a way to have a Multishape that can change between shapes when click, or something of that sort?

Here's my code at the moment:

public class Multishape extends Application
{
    private Text selected;

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

    public void start(Stage stage)
    {
        rectangle rec = new Rectangle(240, 240);

        Group root = new Group();
        root.getChildren().add(rec);
        Scene scene = new Scene(root, 640, 480);
        rec.setFill(Color.color(1,1,1));
        rec.setStroke(Color.color(0,0,0));
        rec.setStrokeWidth(1);

        EventHandler<MouseEvent> STC = (MouseEvent e) ->
        { 
            Circle cir = new Circle(50.0f, Color.RED);
            cir.setFill(Color.color(1,1,1));
            cir.setStroke(Color.color(0,0,0));
            cir.setStrokeWidth(1);
            root.getChildren().add(cir);
            root.getChildren().remove(rec1);
        };

        EventHandler<MouseEvent> CTS = (MouseEvent e) ->
        { 
            Rectangle rec1 = new Rectangle(240, 240);
            rec1.setFill(Color.color(1,1,1));
            rec1.setStroke(Color.color(0,0,0));
            rec1.setStrokeWidth(1);
            root.getChildren().add(rec1);
            root.getChildren().remove(cir);
        };

        rec.addEventHandler(MouseEvent.MOUSE_PRESSED, STC);
        cir.addEventHandler(MouseEvent.MOUSE_PRESSED, CTS); 

        stage.setScene(scene);
        stage.show();
    }
}

Solution

  • The key is giving greater scope to the variables that need it.

    import javafx.application.Application;
    import javafx.event.EventHandler;
    import javafx.scene.Scene;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.StackPane;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Circle;
    import javafx.scene.shape.Rectangle;
    import javafx.stage.Stage;
    
    /**
     * Sedrick (SedJ601)
     * 
     */
    public class App extends Application {
        //Declaring variables here gives them greater scope
        Rectangle rectangle = new Rectangle(240, 240, Color.BLUE);
        Circle circle = new Circle(50, Color.RED);    
        StackPane root = new StackPane();
    
        @Override
        public void start(Stage primaryStage) {
            rectangle.setOnMouseClicked(handleMouseClick);//Set mouse click handler
            circle.setOnMouseClicked(handleMouseClick);//Set mouse click handler
    
            root.getChildren().add(rectangle);//Set initial shape.
    
            Scene scene = new Scene(root, 500, 500);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch();
        }    
    
        EventHandler<MouseEvent> handleMouseClick = new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent t) {
                if(root.getChildren().get(0).equals(rectangle))//if the current shape showing is rectangle change it to circle, else do the opposite
                {
                    root.getChildren().set(0, circle);
                }
                else
                {
                    root.getChildren().set(0, rectangle);
                }
            }
        };
    }