【问题标题】:JavaFx Overlapping mouse eventsJavaFx 重叠鼠标事件
【发布时间】:2018-12-30 14:39:36
【问题描述】:

我正在尝试构建一个棋盘游戏界面,用户可以在其中切换多个时代,每个时代都有自己的棋盘。为此,我创建了 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);
}

【问题讨论】:

  • 将节点的可见性设置为false 实际上并不会删除该节点,因此虽然您看不到它,但它仍然在那里接收事件。对于您的功能,我建议使用StackPane 来固定您的电路板并根据需要重新排列它们。这样,您就可以始终将“活跃”板保持在顶部。
  • @Zephyr 我的根窗格是堆栈窗格,其他是组窗格,因为我使用笛卡尔坐标定位节点。我怎样才能让它发挥作用?用StackPanes 替换我的组窗格会导致节点定位混乱
  • @Zephyr 隐形节点不接收鼠标事件,见docs
  • 发布minimal reproducible example。请记住,我们不需要整个电路板,只需要它的最小表示。
  • 我的立场是正确的。谢谢????

标签: javafx


【解决方案1】:

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

基本上,我们会创建一个StackPane 作为您所有看板的根显示容器。你的“板”可以是任何东西,一个Pane,另一个StackPane,或者一个VBox,就像我的例子一样。这应该允许您继续使用当前的任何布局系统。

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

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

结果:


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

【讨论】:

    猜你喜欢
    • 2022-07-27
    • 1970-01-01
    • 1970-01-01
    • 2013-12-15
    • 2013-09-20
    • 1970-01-01
    • 2010-10-18
    • 2013-05-23
    • 2019-07-11
    相关资源
    最近更新 更多