当前位置: 首页 > 知识库问答 >
问题:

JavaFX使节点部分mouseTransparent

黎玺
2023-03-14

如果我有两个节点堆叠在一起并相互重叠,我如何使顶部的节点成为mouseTransparent(以便底部的节点能够对MouseEvents做出反应),但也让顶部的节点对一些MouseEvents做出反应,比如OnMouseEventer?

<StackPane>
<Pane onMouseEntered="#printA" onMouseClicked="#printB" />
<Pane onMouseEntered="#printC" />
</StackPane>

关于Stackoverflow有许多问题看起来类似,但几乎所有问题都可以通过setmouseTransparent(true)setpickonbounds(true)解决。setmouseTransparent在这里不起作用,从那以后顶部窗格不会打印C。setpickonbounds使窗格在任何地方都是透明的,但透明部分不会打印C,不透明部分阻止下部窗格打印A或B。因此,即使顶部窗格完全透明或完全不透明,也不能解决我的问题。将顶部窗格的可见性设置为false也不会起作用,因为顶部窗格无法打印C。

共有1个答案

夏侯瑞
2023-03-14

我可以考虑的一种方法是,观察鼠标在父节点上的移动,看看鼠标指针是否落在所需节点的检测区域上。这样,您就不需要一个虚拟(透明)节点来进行检测。

所以想法如下:

<StackPane id="parent">
     <Pane onMouseEntered="#printA" onMouseClicked="#printB" />
      // Other nodes in the parent
</StackPane>
  • 像往常一样,在中心节点上有处理程序。
  • 在父节点上添加一个mouseMoved处理程序,以检测鼠标是否进入检测区域。
import javafx.application.Application;
import javafx.geometry.BoundingBox;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class MouseEventsDemo extends Application {
    double detectionSize = 30;

    @Override
    public void start(Stage primaryStage) throws Exception {
        Pane center = getBlock("red");
        center.setOnMouseEntered(e -> System.out.println("Entered on center pane..."));
        center.setOnMouseClicked(e -> System.out.println("Clicked on center pane..."));

        // Simulating that the 'center' is surrounded by other nodes
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.addRow(0, getBlock("yellow"), getBlock("pink"), getBlock("orange"));
        grid.addRow(1, getBlock("orange"), center, getBlock("yellow"));
        grid.addRow(2, getBlock("yellow"), getBlock("pink"), getBlock("orange"));


        // Adding rectangle only for zone visual purpose
        Rectangle zone = new Rectangle(center.getPrefWidth() + 2 * detectionSize, center.getPrefHeight() + 2 * detectionSize);
        zone.setStyle("-fx-stroke:blue;-fx-stroke-width:1px;-fx-fill:transparent;-fx-opacity:.4");
        zone.setMouseTransparent(true);

        StackPane parent = new StackPane(grid, zone);

        VBox root = new VBox(parent);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(20));
        root.setSpacing(20);
        Scene scene = new Scene(root, 500, 500);
        primaryStage.setScene(scene);
        primaryStage.show();

        addDetectionHandler(parent, center);
    }

    private Pane getBlock(String color) {
        Pane block = new Pane();
        block.setStyle("-fx-background-color:" + color);
        block.setMaxSize(100, 100);
        block.setPrefSize(100, 100);
        return block;
    }

    private void addDetectionHandler(StackPane parent, Pane node) {
        final String key = "onDetectionZone";
        parent.setOnMouseMoved(e -> {
            boolean mouseEntered = (boolean) node.getProperties().computeIfAbsent(key, p -> false);
            if (!mouseEntered && isOnDetectionZone(e, node)) {
                node.getProperties().put(key, true);
                // Perform your mouse enter operations on detection zone,.. like changing to edit mode.. or what ever
                System.out.println("Entered on center pane detection zone...");
                node.setStyle("-fx-background-color:green");

            } else if (mouseEntered && !isOnDetectionZone(e, node)) {
                node.getProperties().put(key, false);
                // Perform your mouse exit operations from detection zone,.. like change back to default state from edit mode
                System.out.println("Exiting from center pane detection zone...");
                node.setStyle("-fx-background-color:red");
            }
        });
    }

    private boolean isOnDetectionZone(MouseEvent e, Pane node) {
        Bounds b = node.localToScene(node.getBoundsInLocal());
        double d = detectionSize;
        Bounds detectionBounds = new BoundingBox(b.getMinX() - d, b.getMinY() - d, b.getWidth() + 2 * d, b.getHeight() + 2 * d);
        return detectionBounds.contains(e.getSceneX(), e.getSceneY());
    }
}

然后,您可以简单地将鼠标处理程序添加到检测区域和中心节点。

请查看下面的工作演示:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Polyline;
import javafx.stage.Stage;

public class MouseEventsDemo2 extends Application {
    double detectionSize = 30;

    @Override
    public void start(Stage primaryStage) throws Exception {
        Pane center = getBlock("red");
        center.getChildren().add(new Label("Hello"));
        center.setOnMouseEntered(e -> {
            System.out.println("Entered on center pane...");
            center.setStyle("-fx-background-color:green");
        });
        center.setOnMouseClicked(e -> System.out.println("Clicked on center pane..."));

        // Simulating that the 'center' is surrounded by other nodes
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.addRow(0, getBlock("yellow"), getBlock("pink"), getBlock("orange"));
        grid.addRow(1, getBlock("orange"), center, getBlock("yellow"));
        grid.addRow(2, getBlock("yellow"), getBlock("pink"), getBlock("orange"));

        StackPane parent = new StackPane(grid);

        VBox root = new VBox(parent);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(20));
        root.setSpacing(20);
        Scene scene = new Scene(root, 500, 500);
        primaryStage.setScene(scene);
        primaryStage.show();

        // Building the frame using Polyline node
        Polyline zone = new Polyline();
        zone.setStyle("-fx-fill:grey;-fx-opacity:.5;-fx-stroke-width:0px;");
        zone.setOnMouseEntered(e -> {
            System.out.println("Entered on detection zone...");
            center.setStyle("-fx-background-color:green");
        });
        zone.setOnMouseExited(e -> {
            System.out.println("Exited on detection zone...");
            center.setStyle("-fx-background-color:red");
        });
        zone.setOnMouseClicked(e -> System.out.println("Clicked on detection zone..."));
        parent.getChildren().add(zone);
        parent.layoutBoundsProperty().addListener(p -> updatePolylineZone(center, zone));
        center.layoutBoundsProperty().addListener(p -> updatePolylineZone(center, zone));
        updatePolylineZone(center, zone);
    }

    /**
     * Update the poly line shape to build a frame around the center node if the parent or center bounds changed.
     */
    private void updatePolylineZone(Pane center, Polyline zone) {
        zone.getPoints().clear();

        Bounds b = center.localToParent(center.getBoundsInLocal());
        double s = detectionSize;
        ObservableList<Double> pts = FXCollections.observableArrayList();

//             A-------------------------B
//             |                         |
//             |    a---------------b    |
//             |    |               |    |
//             |    |               |    |
//             |    |               |    |
//             |    d---------------c    |
//             |                         |
//             D-------------------------C

        // Outer square
        pts.addAll(b.getMinX() - s, b.getMinY() - s);  // A
        pts.addAll(b.getMaxX() + s, b.getMinY() - s);  // B
        pts.addAll(b.getMaxX() + s, b.getMaxY() + s);  // C
        pts.addAll(b.getMinX() - s, b.getMaxY() + s);  // D

        // Inner Square
        pts.addAll(b.getMinX() + 1, b.getMaxY() - 1);  // d
        pts.addAll(b.getMaxX() - 1, b.getMaxY() - 1);  // c
        pts.addAll(b.getMaxX() - 1, b.getMinY() + 1);  // b
        pts.addAll(b.getMinX() + 1, b.getMinY() + 1);  // a

        // Closing the loop
        pts.addAll(b.getMinX() - s, b.getMinY() - s);  // A
        pts.addAll(b.getMinX() - s, b.getMaxY() + s);  // D
        pts.addAll(b.getMinX() + 1, b.getMaxY() - 1);  // d
        pts.addAll(b.getMinX() + 1, b.getMinY() + 1);  // a
        pts.addAll(b.getMinX() - s, b.getMinY() - s);  // A

        zone.getPoints().addAll(pts);
    }

    private Pane getBlock(String color) {
        Pane block = new Pane();
        block.setStyle("-fx-background-color:" + color);
        block.setMaxSize(100, 100);
        block.setPrefSize(100, 100);
        return block;
    }
}
 类似资料:
  • 当 Puppet 运行在一个节点上,它需要知道这个节点应该应用了哪些类。 例如,如果这是一个 web 服务器节点,它可能需要包含一个 apache 类。 将类映射到节点的一种简单方法是在配置清单里声明,例如下面是一个 nodes.pp 文件的例子: node web1 { include apache } 另外,你可以使用 外部节点分类器(external node classifier,E

  • 问题就在这里: 我目前必须打印一个a4的横向页面,其中包含当前javaFx场景的“部分”。 我必须打印的部分是BorderPane的部分,我需要打印左侧、中间和底部节点,所以打印的页面应该如下所示: 我将此作为输出(仅供参考): 感谢您的帮助/阅读,感谢您的帮助。 更新01: 这真是让人摸不着头脑... 更新02: 使用快照和imageViews进行新尝试: 我把它除以600(就像Resoluti

  • 我正在尝试将一个矩形拖动到VBox,然后从VBox内部再次拖动它。 如果矩形被放置在目标VBox之外的任何位置,那么它应该将其位置恢复到它所属的位置:如果它是左VBox的子级,则将其重置回其中;如果它是右VBox的子级,则将其重置回右VBox内部。 第一部分工作正常,我可以将其拖到VBox并将其添加为子级。第二部分是我遇到问题的地方。 重现问题的步骤:<br>1)将左矩形拖动到右矩形的顶部(在VB

  • 我有一个具有必要字段的窗格扩展类。它将是“大门”。 调用控制器从FXML加载节点树,并将其作为子级附加到“gate”对象 然后创建并显示一个以“gate”为根节点的新场景。 新的窗口控制器有一个对FXML根节点(“gate”的直接子节点)的引用,他所需要做的就是在其上使用.getparent()来获取“gate”。 但管他呢!它返回null!我做错了什么?我应该通过FXMLLoader设置一个不同

  • 所以我环顾了一下网络,在stackoverflow中有几个问题是定义: 通常,内部节点是任何不是叶子的节点(没有子节点) 非叶/非末端/内部节点-至少有一个度不等于0的子节点或后代节点 据我所知,它是一个节点,而不是一片叶子。 我即将得出结论,根也是一个内部节点,但它的定义似乎有些模糊,如图所示: 二元搜索树中的“内部节点”是什么? 正如这张精彩的图片所示,内部节点是位于树根和树叶之间的节点 如果

  • 在JavaFX中,我试图通过单击并拖动节点来移动它。如果节点不旋转,它工作得很好,但是当我旋转它时,它开始表现得很奇怪。 在45°左右,当我移动它时,它开始抖动,在60°时,它剧烈地来回抖动。在90°时,只要我开始移动节点,它就会飞离屏幕。 下面是我用来旋转和移动节点的代码。它来自连接到节点的鼠标侦听器。 编辑:这是一些示例输出,以及显示不同节点的图片。 未旋转且缓慢向左移动时的输出: 旋转时缓慢