navy1978
navy1978

Reputation: 1439

JavaFx: check if the mouse is on node's children

I would like to know if there is a way to determine if the mouse collides with a node's children, in less words, In the example below, If I click on the Group the output is:

"Group!"

If I click on the image the output is:

"Group!
Image!"

Is there a way to put code in the "group.setOnMousePressed" in order to check if the mouse in on the image and in that case don't do anything and just execute what is in the "group.setOnMousePressed", in order to have this output clicking on image:

 "Image!"

Please find below a SSCCE:

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class SSCCEForSO extends Application {



    @Override
    public void start(Stage primaryStage) {

        AnchorPane anchor= new AnchorPane();
        Group group= new Group();

        ImageView image= new ImageView();

        image.setImage(ImageUtil.getImage("wave.png"));
        ImageView image2= new ImageView();
        image2.setImage(ImageUtil.getImage("pause15.png"));
        HBox hBox = new HBox();
        hBox.setPrefSize(200, 200);
        hBox.setAlignment(Pos.CENTER);
        hBox.setStyle("-fx-padding: 10;-fx-background-color: firebrick;-fx-background-radius: 5;");

        hBox.getChildren().add( image);
        hBox.getChildren().add( image2);

        group.getChildren().add(hBox);

        group.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                System.out.println("Group!");

            }
        });

        image2.onMouseClickedProperty().set(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                System.out.println("Image!");
            }

        });


        anchor.getChildren().add(group);
        Scene scene = new Scene(anchor, 800, 600);



        primaryStage.setScene( scene);
        primaryStage.show();

    }

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

Thank you in advance

Upvotes: 2

Views: 4124

Answers (1)

jewelsea
jewelsea

Reputation: 159291

Suggested Solution: Consume the Event

Consume the mouse event when you handle it in your on clicked handler for the image:

image2.setOnMouseClicked(new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent mouseEvent) {
        mouseEvent.consume();
        System.out.println("Image! " + mouseEvent.getTarget());
    }
});

This will prevent the event from continuing to bubble up the event dispatch chain. Read the section of the Oracle JavaFX documentation on handling events if you need to understand what this actually means.

Alternate Solution: Check the Event Target

Note, I also added mouseEvent.getTarget() to the handler. You can use the result of this call to evaluate the target of the event and take action based upon that. For example, the following code would also work:

hBox.setOnMouseClicked(new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent mouseEvent) {
        if (mouseEvent.getTarget() == hBox) {
            System.out.println("hBox! " + mouseEvent.getTarget());
        } else {
            System.out.println("hBox Ignored! " + mouseEvent.getTarget());
        }
    }
});

image2.setOnMouseClicked(new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent mouseEvent) {
        System.out.println("Image! " + mouseEvent.getTarget());
    }
});

Notes for the above code:

  1. I changed the handler settings to all consistently use onMouseClicked rather than one onMousePressed handler and one onMouseClicked handler. This is important because mouse clicks and mouse presses are distinct events.
  2. I used set the onClickHandler on the hBox rather than the enclosing group because the hBox is actually the target of the event rather than the enclosing group. The hBox covers the group completely, so the user cannot directly click on the group as an event target, they can only click on the covering hBox.

Executable Sample

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.image.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.stage.Stage;

public class SSCCEForSO extends Application {

    @Override
    public void start(Stage primaryStage) {

        AnchorPane anchor= new AnchorPane();
        Group group= new Group();

        ImageView image= new ImageView();

        image.setImage(new Image("http://icons.iconarchive.com/icons/custom-icon-design/pretty-social-media-2/64/Google-wave-icon.png"));
        ImageView image2= new ImageView();
        image2.setImage(new Image("http://icons.iconarchive.com/icons/custom-icon-design/pretty-office-8/64/Pause-icon.png"));
        HBox hBox = new HBox();
        hBox.setPrefSize(200, 200);
        hBox.setAlignment(Pos.CENTER);
        hBox.setStyle("-fx-padding: 10;-fx-background-color: firebrick;-fx-background-radius: 5;");

        hBox.getChildren().add( image);
        hBox.getChildren().add( image2);

        group.getChildren().add(hBox);

        group.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                System.out.println("Group!" + mouseEvent.getSource());
            }
        });

        image2.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                System.out.println("Image!" + mouseEvent.getSource());
                mouseEvent.consume();
            }
        });

        anchor.getChildren().add(group);
        Scene scene = new Scene(anchor, 800, 600);

        primaryStage.setScene( scene);
        primaryStage.show();

    }

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

Upvotes: 5

Related Questions