JavaFx重叠鼠标事件

时间:2018-12-30 14:39:36

标签: javafx

我正在尝试构建一个棋盘游戏界面,用户可以在多个时代之间切换,每个时代都有自己的棋盘。为此,我要创建4个不同的板,每个板都在其自己的窗格中,并且切换节点的可见性并禁用未使用的节点。我遇到的问题是我正在使用鼠标事件处理程序来查看用户单击的位置仅在顶层(即最后一个渲染的层)上进行。即使启用了下面的事件处理程序,它们也不会起作用。 这是我写的:

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);
    }
}

这是我用来切换正在使用的电路板的内容:     禁用

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

启用

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

1 个答案:

答案 0 :(得分:0)

也许使用StackPane是这里的解决方案。您的问题并没有包含太多代码来显示您的所有上下文,但是下面的MCVE可能有助于证明您的想法。

基本上,我们创建一个StackPane作为您所有面板的根显示容器。您的“木板”可以是任何东西,例如Pane,另一个StackPaneVBox,例如我的示例。这应该可以让您继续使用当前使用的任何布局系统。

需要注意的一件事是,似乎每个板都需要设置背景,或者较低的板将显示出来并可以接受鼠标事件。

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);
    }
}
  

结果:

screenshot


诚然,我不熟悉您在评论中提到的笛卡尔坐标,因此也许这对您不起作用。在您的问题中添加更多代码/上下文可能有助于我们更好地缩小问题范围。