2

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

navy1978
  • 1,411
  • 1
  • 15
  • 35

1 Answers1

5

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);
    }
}
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • Thank you for your answer, but putting : image2.onMouseClickedProperty().set(new EventHandler() { @Override public void handle(MouseEvent mouseEvent) { mouseEvent.consume(); System.out.println("Image!"); } }); Doens't do the trick, the output is still printing both "Group! Image!" – navy1978 Jan 19 '16 at 21:58
  • Definitely works for me, I'll add an executable sample. – jewelsea Jan 19 '16 at 22:03
  • My guess is that you were getting issues with the consume method because you are logging "Group!" in an onMousePressed handler rather than an onClickedHandler (in which you were consuming the event). A mouse pressed event is different from a mouse clicked event, so if you consume the mouse clicked event, it would have no impact on a subsequent mouse pressed event. – jewelsea Jan 19 '16 at 22:08
  • The updated you provided , don't work again but gave me the answer... use getTarget is what I need , but in your code Group will be never printed out because getTarget return always Hbox that is on top of the group and have the same size of it... In any case I solved I have just to change the check! Thank you! – navy1978 Jan 19 '16 at 22:08
  • Your guess is exact! You are right! Thanks! I'm learning something on the events also reading the link you suggested in the first answer... ;) – navy1978 Jan 19 '16 at 22:09
  • The Executable Sample you provided works like a charm ;) – navy1978 Jan 19 '16 at 22:14
  • Updated answer to use a hBox in the sample target method processor (as suggested by navy) rather than a group. – jewelsea Jan 19 '16 at 22:23