2

I am trying to learn javafx. I did most of the code but I am having trouble with the start method.

What I wanted to do was add spots to the screen by clicking on it. And if I press either 1 or 0 future spots that will be added will change to some different color. Therefore, I know that I must use setOnMouseClicked and setOnKeyPressed methods but there isn't much on the internet on it.

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;


public class Spots extends Application {

    public static final int SIZE = 500;    
    public static final int SPOT_RADIUS = 20;    
    private LinkedList<Spot> spotList;    
    private Color color;

    public static void main(String...args) {
        launch(args);
    }

    public void start(Stage stage) {

        stage.setTitle("Spots");    
        dotList = new SinglyLinkedList<>();        
        Group root = new Group();
        Scene scene = new Scene(root, 500, 500, Color.BLACK);
        Spot r;

        // ...    

        stage.show(); 
    }

    private class Spot extends Circle {

        public Spot(double xPos, double yPos) {
            super(xPos, yPos, SPOT_RADIUS);
            setFill(color);
        }

        public boolean contains(double xPos, double yPos) {
            double dx = xPos - getCenterX();
            double dy = yPos - getCenterY();
            double distance = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
            return distance <= SPOT_RADIUS;
        }        
    }
}
Wolfgang Fahl
  • 15,016
  • 11
  • 93
  • 186
Lin
  • 23
  • 1
  • 4

3 Answers3

4

The reason the circle is not accepting is that it is not focused. For nodes to respond to key events they should be focusTraversable. You can do that by calling setFocusTraversable(true) on the node. I edited your start() method and here is the code I ended up with.

public void start(Stage primaryStage) throws Exception {

    Pane pane = new Pane();
    final Scene scene = new Scene(pane, 500, 500);
    final Circle circle = new Circle(250, 250, 20);
    circle.setFill(Color.WHITE);
   circle.setStroke(Color.BLACK);
    pane.getChildren().add(circle);
     circle.setFocusTraversable(true);
    circle.setOnKeyPressed(new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent e) {
            if ((e.getCode() == KeyCode.UP) && (circle.getCenterY() >= 5)) {
                circle.setCenterY(circle.getCenterY() - 5);
            }

            else if ((e.getCode() == KeyCode.DOWN && (circle.getCenterY() <= scene.getHeight() - 5))) {
                circle.setCenterY(circle.getCenterY() + 5);
            }
            else if ((e.getCode() == KeyCode.RIGHT) && (circle.getCenterX() <= scene.getWidth() - 5)) {
                circle.setCenterX(circle.getCenterX() + 5);
            }
            else if ((e.getCode() == KeyCode.LEFT && (circle.getCenterX() >= 5))) {

                circle.setCenterX(circle.getCenterX()-5);
            }
        }
    });

  //creates new spots by clicking anywhere on the pane
    pane.setOnMouseClicked(new EventHandler<MouseEvent>() {  
      public void handle(MouseEvent event) {
            double newX = event.getX(); //getting the x-coordinate of the clicked area
            double newY = event.getY(); //getting the y-coordinate of the clicked area

            Circle newSpot = new Circle(newX, newY,20);
            newSpot.setFill(Color.WHITE);
            newSpot.setStroke(Color.BLACK);
            pane.getChildren().add(newSpot);

        }
    });

    primaryStage.setTitle("Move the circle");
    primaryStage.setScene(scene);
    primaryStage.show();
}

Also take look at the answers for the following links:

Community
  • 1
  • 1
xabush
  • 849
  • 1
  • 13
  • 29
  • Thank you! But how do I make it that when I click on the screen a new spot appears? – Lin Apr 18 '15 at 23:05
  • My underlying problem is the mouse event. – Lin Apr 18 '15 at 23:11
  • You're welcome. I suggest you look at this [tutorial](http://code.makery.ch/library/javafx-8-tutorial/part1/). It teaches you by creating a JavaFX app from scratch. – xabush Apr 18 '15 at 23:28
  • Ty for the link! I have a last question. If I wanted to use group instead of pane how can I go about doing that? – Lin Apr 18 '15 at 23:54
  • Lin, why would you want to use a Group instead of a Pane? (If you are not sure of the answer to my question, you might want to ask that as a new question). – jewelsea Apr 19 '15 at 00:01
1

Solution Approach

You can monitor the scene for key typed events and switch the color mode based on that. You can place an mouse event handler on your scene root pane and add a circle (of the appropriate color for the prevailing color mode) to the scene when the user clicks anywhere in the pane.

Sample Code

spots

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

// Java 8+ code.
public class Spots extends Application {

    private static final int SIZE = 500;
    private static final int SPOT_RADIUS = 20;

    private Color color = Color.BLUE;

    public void start(Stage stage) {
        Pane root = new Pane();

        root.setOnMouseClicked(event ->
                root.getChildren().add(
                        new Spot(
                                event.getX(),
                                event.getY(),
                                color
                        )
                )
        );

        Scene scene = new Scene(root, SIZE, SIZE, Color.BLACK);
        scene.setOnKeyTyped(event -> {
            switch (event.getCharacter()) {
                case "0":
                    color = Color.BLUE;
                    break;
                case "1":
                    color = Color.RED;
                    break;
            }
        });

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

    private class Spot extends Circle {
        public Spot(double xPos, double yPos, Color color) {
            super(xPos, yPos, SPOT_RADIUS);
            setFill(color);
        }
    }

    public static void main(String... args) {
        launch(args);
    }
}

Further Info

jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • Thank you! If I were to use group instead of Pane how will I go about doing that? I want to take advantage of the dotList I provided. – Lin Apr 18 '15 at 23:58
  • Using a Pane or a Group is irrelevant with respect to your dotList. Both Pane and Group are [Parents](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/Parent.html) and both have children, so the implementation with respect to child list handing is not different if you use a Pane or a Group. – jewelsea Apr 19 '15 at 00:02
0

Generally, you'd use setOnAction as shown in the Oracle tutorials.

Example:

    btn.setOnAction(new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
            System.out.println("Hello World");
        }
    });

If the particular Node you're trying to use does not have a clickHandler method, try doing something like this (on Group for example):

    group.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent event) {
            System.out.println("Hello!");
        }
    });
Renato
  • 12,940
  • 3
  • 54
  • 85