简体   繁体   中英

JavaFx Overlapping mouse events

I'm trying to build a board game interface where the user can switch between multiple eras, each one with its own board. To do so, I'm creating 4 different board, each within its own pane, and I'm toggling the nodes Visibility and disabling the nodes that aren't being used. The problem I have is the mouse event handlers I'm using to see where the user is clicking only work on the top layer, the last one that was rendered. The event Handlers underneath don't work even if they are enabled. Here's what I wrote:

static EventHandler<MouseEvent> eventMouseClickRoad = new EventHandler<MouseEvent>() { 
    @Override 
    public void handle(MouseEvent e) { 
        final Shape innerShape = (Shape) (e.getTarget());
        System.out.println("click");
        Color color = (Color) innerShape.getFill();
        if(color.getOpacity() != 1)
        {
            innerShape.setFill(Color.RED);
            //and do the data treatment
        }
    }
}; 


public void boardControler(Vector2DList sideList,PointList hexEdge,Pane groupPane,float scaleX, float scaleY, float buttonSize)
{
    //set road button
    for(Vector2D v : sideList.getVectorList()){
    Path mypath = new Path(new MoveTo(v.getP1().getX(),v.getP1().getY()),new LineTo(v.getP2().getX(),v.getP2().getY()));
    groupPane.getChildren().add(mypath);
    }
    for(Vector2D v : sideList.getVectorList()){
        float midX=(v.getP1().getX()+v.getP2().getX())/2;
        float diffY=v.getP1().getY()-v.getP2().getY();
        float diffX=v.getP1().getX()-v.getP2().getX();
        Rectangle rectangle = new Rectangle(midX-buttonSize/2,midY-Math.abs(diffY)+buttonSize+(Math.abs(diffY)-scaleY/4),buttonSize,(scaleY/2)-(buttonSize*2));
        rectangle.setRotate(Math.toDegrees(Math.atan(diffY/diffX))+90);
        rectangle.setFill(Color.TRANSPARENT);
        rectangle.addEventFilter(MouseEvent.MOUSE_ENTERED, Event.eventMouseEntered);
        rectangle.addEventFilter(MouseEvent.MOUSE_EXITED, Event.eventMouseExit);
        rectangle.addEventFilter(MouseEvent.MOUSE_CLICKED, Event.eventMouseClickRoad);
        groupPane.getChildren().add(rectangle);
    }
}

And this is what i use to toggle the board that's being used: to disable

for(Node n : groupPane2.getChildren())
{
    n.setDisable(true);
    n.setManaged(false);
    n.setVisible(false);
}

to enable

for(Node n : groupPane2.getChildren())
{
    n.setDisable(false);
    n.setManaged(true);
    n.setVisible(true);
}

Perhaps using a StackPane would be the solution here. Your question doesn't include much code to show all of your context, but the MCVE below may help to demonstrate the idea.

Basically, we create a StackPane as our root display container for all of your boards. Your "boards" can be anything, a Pane , another StackPane , or a VBox like in my example. This should allow you to continue using whatever layout system you currently are.

One thing to note, it appears that each board will need to have a background set, or the lower boards will show through and may accept mouse events.

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class StackPaneSample extends Application {

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

    private static StackPane stackPane = new StackPane();

    @Override
    public void start(Stage primaryStage) {

        // Simple interface
        VBox root = new VBox(5);
        root.setPadding(new Insets(10));
        root.setAlignment(Pos.CENTER);

        // Create our StackPane
        stackPane.setStyle("-fx-border-color: black");
        VBox.setVgrow(stackPane, Priority.ALWAYS);

        // Let's create 3 "boards" for our StackPane. A background color seems necessary to hide layers below the top one
        VBox board1 = new VBox() {{
            setStyle("-fx-background-color: whitesmoke");
            setAlignment(Pos.CENTER);
            setUserData("Board #1");
            getChildren().add(new Label((String) getUserData()));
        }};
        VBox board2 = new VBox() {{
            setStyle("-fx-background-color: whitesmoke");
            setAlignment(Pos.CENTER);
            setUserData("Board #2");
            getChildren().add(new Label((String) getUserData()));
        }};
        VBox board3 = new VBox() {{
            setStyle("-fx-background-color: whitesmoke");
            setAlignment(Pos.CENTER);
            setUserData("Board #3");
            getChildren().add(new Label((String) getUserData()));
        }};
        stackPane.getChildren().add(board1);
        stackPane.getChildren().add(board2);
        stackPane.getChildren().add(board3);

        // Create three buttons that will switch between the boards
        Button btnBoard1 = new Button("Board #1");
        Button btnBoard2 = new Button("Board #2");
        Button btnBoard3 = new Button("Board #3");
        HBox hbButtons = new HBox(20) {{
            setAlignment(Pos.CENTER);
            setPadding(new Insets(5));
            getChildren().addAll(btnBoard1, btnBoard2, btnBoard3);
        }};

        // Finish out layout
        root.getChildren().addAll(
                stackPane,
                new Separator(Orientation.HORIZONTAL),
                hbButtons
        );

        // ** Now let's add our functionality **

        // Print out which board has been clicked upon
        // We need to first cast our List to VBox
        for (Node vbox : stackPane.getChildren()) {
            vbox.setOnMouseClicked(event -> System.out.println("Clicked on " + vbox.getUserData()));
        }

        // Set the buttons to set the top board
        btnBoard1.setOnAction(event -> selectBoard(board1));
        btnBoard2.setOnAction(event -> selectBoard(board2));
        btnBoard3.setOnAction(event -> selectBoard(board3));

        // Show the Stage
        primaryStage.setWidth(400);
        primaryStage.setHeight(300);
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

    // Method to remove the board and readd it, placing it on top of all others.
    private static void selectBoard(VBox board) {
        stackPane.getChildren().remove(board);
        stackPane.getChildren().add(board);
    }
}

The Result:

截图


I am, admittedly, not familiar with the Cartesian coordinates you mention in your comment, so perhaps this won't work for you. Adding more code/context to your question might help us narrow down the issue better.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM