0

JavaFx: I have a HBox with a Button in it ,inside a Group, and I would like to manage the "MousePressed" event differently for each node. At the moment if I handle the same event for all the nodes, it is always catches by the parent node (Group).

Is there a way to do that? For example is there a way to determine if the mouse coordinates are over the node's children (HBox in my example)?

This is an example of what I need:

enter image description here

If I click on Group I want to hide the HBox if the coordinate of mouse don't collide with HBox, If I click on HBox, Hbox doesn't need to be hide, and If I click on the Button (implemented as an ImageView) I need to execute code without hide the HBox.

So for example what I would like to do is something like that:

    '
Group group= new Group();
HBox hBox = new HBox();
ImageView image= new ImageView();
hBox.getChildren().add(image);
hBox.toFront();
group.getChildren().add(hBox);
image.setImage(ImageUtil.getImage("img.png"));
group.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                        <if not collide with HBOX hide HBOX.>

                    }
                });
box.setOnMousePressed(new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent mouseEvent) {
                        <do other things without hidding HBOX.>

                    }
                });



image.onMouseClickedProperty().set(new EventHandler<MouseEvent>() {
                                @Override
                                public void handle(MouseEvent mouseEvent) {
        <do something>
                                    }

                            });

' Where group is inside an AncorPane designed with sceneBuilder '

@FXML
Group group;

'

Thank you for your help.

navy1978
  • 1,411
  • 1
  • 15
  • 35
  • Just register different handlers with each of the child nodes. Maybe it would help to post some code. – James_D Jan 17 '16 at 14:38
  • I have already registered two handlers one for the parent (Group) and one for the children (HBox), the problem is that everything is caught by the first (one linked to Group).... – navy1978 Jan 17 '16 at 14:44
  • Post a [MCVE]. It's difficult (perhaps impossible) to know what's going wrong without a code example. – James_D Jan 17 '16 at 14:45
  • Thanks for you answer, I have updated my question, I hope it is more clear. – navy1978 Jan 18 '16 at 05:45
  • 1
    Not really: it's not really possible to understand what's happening without the layout code. Please write a [MCVE]. – James_D Jan 18 '16 at 05:51
  • I have updated again, with how the layout is created... I hope this time it is better... I cannot provide a verifiable example ( I would need to attach the scene builder xml and all the rest), but I think now should be enough – navy1978 Jan 18 '16 at 06:04
  • voting to close .. it's **ALWAYS** possible to provide an example (as described in the reference given by @James_D ) that demonstrates a problem. Without, any answer is a guessing game that's wasting everybody's time. – kleopatra Jan 18 '16 at 23:32
  • On top of that, the code presented doesn't generate the layout shown in the diagram. A `Group` takes on the union of the bounds of its child nodes, so with the code given there is no part of the `Group` that does not contain the `HBox`. – James_D Jan 18 '16 at 23:38
  • I agree, please close it and I will try to open a new one providing a SSCCE. Thank you in any case for all your answers and your patience... – navy1978 Jan 19 '16 at 21:20
  • Done, you can find the new one here: http://stackoverflow.com/questions/34887546/javafx-check-if-the-mouse-is-on-nodes-children – navy1978 Jan 19 '16 at 21:49

1 Answers1

2

Your question is unclear, but nontheless, if it helps you:

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

// the magic: use setPickOnBounds(false);
public class LayersWithMouseEvents extends Application {


    @Override
    public void start(Stage primaryStage) {

        // root
        StackPane root = new StackPane();

        // layers
        Pane bottomLayer = new Pane();
        Pane topLayer = new Pane();

        // bottom: layer1, top: layer2
        root.getChildren().addAll(bottomLayer, topLayer);

        // layer 1 objects
        Rectangle rectangle = new Rectangle( 100,100,100,100);
        rectangle.setFill(Color.GREEN);
        rectangle.setOnMousePressed(e -> System.out.println("Rectangle 0: " + e));
        bottomLayer.getChildren().add(rectangle);

        // layer 2 objects
        rectangle = new Rectangle( 50,50,50,50);
        rectangle.setFill(Color.RED);
        rectangle.setOnMousePressed(e -> System.out.println("Rectangle 1: " + e));
        topLayer.getChildren().add(rectangle);

        rectangle = new Rectangle( 125,125,50,50);
        rectangle.setFill(Color.RED);
        rectangle.setOnMousePressed(e -> System.out.println("Rectangle 2: " + e));
        topLayer.getChildren().add(rectangle);

        rectangle = new Rectangle( 200,200,50,50);
        rectangle.setFill(Color.RED);
        rectangle.setOnMousePressed(e -> System.out.println("Rectangle 3: " + e));
        topLayer.getChildren().add(rectangle);

        // layer 1 event handler
        bottomLayer.setOnMousePressed(e -> System.out.println("Layer 1: " + e));

        // layer 2 event handler
        topLayer.setOnMousePressed(e -> System.out.println("Layer 2: " + e));


        // this is the magic that allows you to click on the layer1 object event though layer 2 is on top of layer 1
        // but ONLY(!) as long as the layer is transparent. if you add e. g. this it won't work anymore to click through to layer 1:
        //   layer2.setStyle( "-fx-background-color:yellow");
        topLayer.setPickOnBounds(false);

        primaryStage.setScene(new Scene(root, 800, 600));
        primaryStage.show();

    }

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

Another example would be to add the listener to the parent, e. g. the scene and check the event's target like this:

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class LayersWithMouseEvents2 extends Application {


    @Override
    public void start(Stage primaryStage) {

        Rectangle rectangle = new Rectangle( 100,100,100,100);
        rectangle.setFill(Color.GREEN);

        HBox hBox = new HBox();
        hBox.setPrefSize(200, 200);
        hBox.setStyle("-fx-background-color:yellow");
        hBox.getChildren().add( rectangle);

        Group root = new Group();
        root.getChildren().add(hBox);

        primaryStage.setScene(new Scene(root, 800, 600));
        primaryStage.show();

        primaryStage.getScene().setOnMousePressed(e -> System.out.println("Scene: " + e));
    }

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

Depending on where you click you get:

Scene: MouseEvent [source = javafx.scene.Scene@2c69fd61, target = javafx.scene.Scene@2c69fd61, eventType = MOUSE_PRESSED, consumed = false, x = 295.0, y = 134.0, z = 0.0, button = PRIMARY, primaryButtonDown, pickResult = PickResult [node = null, point = Point3D [x = 295.0, y = 134.0, z = 0.0], distance = 1119.6152422706632]
Scene: MouseEvent [source = javafx.scene.Scene@2c69fd61, target = HBox@5a40dda8, eventType = MOUSE_PRESSED, consumed = false, x = 148.0, y = 134.0, z = 0.0, button = PRIMARY, primaryButtonDown, pickResult = PickResult [node = HBox@5a40dda8, point = Point3D [x = 148.0, y = 134.0, z = 0.0], distance = 1119.6152422706632]
Scene: MouseEvent [source = javafx.scene.Scene@2c69fd61, target = Rectangle[x=100.0, y=100.0, width=100.0, height=100.0, fill=0x008000ff], eventType = MOUSE_PRESSED, consumed = false, x = 52.0, y = 54.0, z = 0.0, button = PRIMARY, primaryButtonDown, pickResult = PickResult [node = Rectangle[x=100.0, y=100.0, width=100.0, height=100.0, fill=0x008000ff], point = Point3D [x = 152.0, y = 154.0, z = 0.0], distance = 1119.6152422706632]

And with the visibility toggling it could be like this:

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class LayersWithMouseEvents2 extends Application {

    boolean hBoxVisible = true;

    @Override
    public void start(Stage primaryStage) {


        Rectangle rectangle = new Rectangle( 100,100,100,100);
        rectangle.setFill(Color.GREEN);

        HBox hBox = new HBox();
        hBox.setPrefSize(200, 200);
        hBox.setStyle("-fx-background-color:yellow");
        hBox.getChildren().add( rectangle);

        Group root = new Group();
        root.getChildren().add(hBox);

        Scene scene = new Scene(root, 800, 600);

        scene.setOnMousePressed(e -> {

            System.out.println("Scene: " + e);

            if( e.getTarget() == hBox) {
                System.out.println( "HBox clicked");
            }

            if( e.getTarget() == rectangle) {
                System.out.println( "Rectangle clicked");
            }

            if( e.getTarget() == scene) {
                System.out.println( "Scene clicked");

                hBoxVisible = !hBoxVisible;

                hBox.setVisible(hBoxVisible);}

        });

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

    }

    public static void main(String[] args) {
        launch(args);
    }
}
Roland
  • 18,114
  • 12
  • 62
  • 93
  • Thank you for your answer But this is not what I need I have updated my question adding an example of what I need.. – navy1978 Jan 18 '16 at 05:35
  • I updated the answer. – Roland Jan 18 '16 at 07:13
  • @navy1978 that's exactly why a SSCCE is required: without, it's a guessing game of what exactly you want to achieve and how exactly your code goes wrong. Note that it **ALWAYS** possible to provide such an example that's stripped down to the barest minimum that demonstrates a problem! – kleopatra Jan 18 '16 at 23:30