Events JavaFX-使两个重叠组件之一的鼠标单击透明 情况:

Events JavaFX-使两个重叠组件之一的鼠标单击透明 情况:,events,javafx,event-handling,mouseevent,overlapping,Events,Javafx,Event Handling,Mouseevent,Overlapping,我有两个不相关的重叠组件(来自不同父节点的不同节点)。前端组件吸收了我的问题所在的所有事件。组件的层次结构无法更改,我希望通过编程解决这个问题 我想要什么: 我希望前面的组件对鼠标点击事件是透明的(类似于MouseTransparent(true)行为,但仅适用于鼠标点击),这样背景组件就可以捕获右键点击事件 我尝试的是: 删除前端组件的EventHandler-无效 在计算背景组件后触发事件-非常不稳定 有没有办法使前端组件对特定事件半透明 [编辑-代码和插图] 注意:我想找到一种方法来

我有两个不相关的重叠组件(来自不同父节点的不同节点)。前端组件吸收了我的问题所在的所有事件。组件的层次结构无法更改,我希望通过编程解决这个问题

我想要什么: 我希望前面的组件对鼠标点击事件是透明的(类似于MouseTransparent(true)行为,但仅适用于鼠标点击),这样背景组件就可以捕获右键点击事件

我尝试的是:
  • 删除前端组件的EventHandler-无效
  • 在计算背景组件后触发事件-非常不稳定
有没有办法使前端组件对特定事件半透明

[编辑-代码和插图] 注意:我想找到一种方法来忽略前面的鼠标左键

public class Main extends Application {

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        initScene(primaryStage);
    }

    public void initScene(Stage primaryStage) {
        /* Initialization */
        StackPane root = new StackPane();
        Group frontContainer = new Group();
        Group backContainer = new Group();
        Scene _scene = new Scene(root, 500, 500);
        Rectangle frontComponent = new Rectangle(180, 180);
        Rectangle backComponent = new Rectangle(200, 200);
        frontComponent.setFill(Color.GREY);
        backComponent.setFill(Color.ORANGE);

        /* Scene Graph construction */
        frontContainer.getChildren().add(frontComponent);
        backContainer.getChildren().add(backComponent);
        root.getChildren().add(backContainer);
        root.getChildren().add(frontContainer);
        backContainer.toBack();
        frontContainer.toFront();

        // --- MouseEvents Handlers
        // --------------------------------------------------------
        frontContainer.setOnMouseClicked((mouseClicked) -> {
            if (mouseClicked.getButton() == MouseButton.PRIMARY)
                System.out.println("FrontComponent right click");
        });

        frontContainer.setOnDragDetected((mouseDrag) -> {
            // Does something very important for a DragNDrop feature that
            // depends on Right Mouse Click
        });

        backComponent.setOnMouseClicked((mouseClicked) -> {
            if (mouseClicked.getButton() == MouseButton.SECONDARY)
                System.out.println("BackComponent left click");
        });
        // ------------------------------------------------------------------------------------

        // frontContainer.setOnMouseClicked(null); /* Disables the handling but
        // still consumes the event */

        primaryStage.setScene(_scene);
        primaryStage.show();
    }
}

经过深思熟虑,我发现在不改变整个层次结构的情况下唯一可行的解决方案是改变事件调度。 可以找到有关事件处理的更多信息

我通过向容器的父节点应用一个实例来改变事件处理。EventFilter在EventHandler之前被调用,因此我捕获了MouseClick事件并对其进行了处理。当我计算出back组件位于背景中时,我使用了frontComponent上的leftClick,然后向backComponent触发了一个新的MouseClick事件

这个新的firedEvent有一个目标我的后组件,它忽略了我的前组件,这正是我需要的

// --- MouseEvents Handlers --------------------------------------------------------
    frontContainer.setOnMouseClicked((mouseClicked) -> {
        if (mouseClicked.getButton() == MouseButton.PRIMARY)
            System.out.println("FrontComponent right click");
        if (mouseClicked.getButton() == MouseButton.SECONDARY)
            System.out.println("FrontComponent left click");
    });

    frontContainer.setOnDragDetected((mouseDrag) -> {
        // Does something very important for a DragNDrop feature that
        // depends on Right Mouse Click
    });

    backComponent.setOnMouseClicked((mouseClicked) -> {
        if (mouseClicked.getButton() == MouseButton.SECONDARY)
            System.out.println("BackComponent left click");
    });

    root.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {

        @Override
        public void handle(MouseEvent event) {
            System.out.println("click FILTERED");
            if (event.getButton() == MouseButton.SECONDARY && !dispatchFlag) {
                if (event.getX() >= backContainer.getLayoutX()
                        && backContainer.getLayoutX() + backComponent.getWidth() >= event.getX()) {
                    System.out.println("It is behind me !");

                    MouseEvent monEvent = new MouseEvent(event.getSource(), backContainer, MouseEvent.MOUSE_CLICKED,
                            event.getSceneX(), event.getY(), event.getScreenX(), event.getScreenY(),
                            event.getButton(), event.getClickCount(), false, false, false, false,
                            event.isPrimaryButtonDown(), event.isMiddleButtonDown(), event.isSecondaryButtonDown(),
                            event.isSynthesized(), event.isPopupTrigger(), event.isStillSincePress(),
                            event.getPickResult());
                    event.consume();
                    dispatchFlag = true;
                    Event.fireEvent(backComponent, monEvent);
                    System.out.println("Event dispatched !");

                }

            }

            dispatchFlag = false;

        }
    });

    // ------------------------------------------------------------------------------------
/--MouseEvents处理程序--------------------------------------------------------
frontContainer.setOnMouseClicked((鼠标单击)->{
if(mouseClicked.getButton()==MouseButton.PRIMARY)
System.out.println(“FrontComponent右键单击”);
if(mouseClicked.getButton()==MouseButton.SECONDARY)
System.out.println(“FrontComponent左键单击”);
});
frontContainer.setOnDragDetected((鼠标拖动)->{
//对DragNDrop功能执行非常重要的操作
//取决于鼠标右键单击
});
backComponent.setOnMouseClicked((鼠标单击)->{
if(mouseClicked.getButton()==MouseButton.SECONDARY)
System.out.println(“BackComponent左键单击”);
});
root.addEventFilter(MouseEvent.MOUSE_单击,新建EventHandler()){
@凌驾
公共无效句柄(MouseeEvent事件){
System.out.println(“单击过滤”);
if(event.getButton()==MouseButton.SECONDARY&&!dispatchFlag){
如果(event.getX()>=backContainer.getLayoutX())
&&backContainer.getLayoutX()+backComponent.getWidth()>=事件.getX()){
System.out.println(“它在我后面!”);
MouseEvent monEvent=新的MouseEvent(event.getSource(),backContainer,MouseEvent.MOUSE_单击,
event.getSceneX(),event.getY(),event.getScreenX(),event.getScreenY(),
event.getButton(),event.getClickCount(),false,false,false,
event.isPrimaryButtonDown(),event.isMiddleButtonDown(),event.isSecondaryButtonDown(),
event.isSynthesized(),event.isPopupTrigger(),event.isStillSincePress(),
event.getPickResult());
event.consume();
dispatchFlag=true;
事件。fireEvent(backComponent,monEvent);
System.out.println(“事件已调度!”);
}
}
dispatchFlag=false;
}
});
// ------------------------------------------------------------------------------------

这种溶液与胺溶液有些相似。它没有定义事件过滤器,只是在前端组件的事件处理程序中拦截事件,并将鼠标单击事件转发给后端组件。也许事件过滤器方法是首选的,但是这个答案中的处理程序似乎可以完成任务,至少在这种情况下是这样

要确定后部组件是否位于前部组件上单击的点下方,请使用以下逻辑:

boolean isInBackComponent = backComponent.contains(
        backComponent.sceneToLocal(
                mouseClicked.getSceneX(), mouseClicked.getSceneY()
        )
);
示例代码:


我很好奇是否可以使用if语句在左键单击或右键单击的基础上向前移动正确的节点。或者您可以在顶部节点onClick中同时处理右键和左键单击吗?您应该创建一个最小、完整且可验证的示例。可能是@SedrickJefferson的复制品这是个好主意,我没有想过动态地切换组件的Z顺序。不幸的是,他们都使用右键点击,所以也许我可以使用另一种方式触发订单切换…@HypnicJerk这两个主题非常相似,但这不是我想要的。ThanksA正确的方法是将这两个组件都包含在一个层次结构中,例如us FrontComponent>BackComponent,以便在不计算位置的情况下使用EventFilter。但由于上下文要求不改变层次结构,因此这是最好的解决方案。正确的方法是在层次结构中包括这两个组件,例如us FrontComponent>BackComponent,以便在不计算位置的情况下使用EventFilter。但是,由于上下文不改变层次结构,这是最好的解决方案。正确的方法是在层次结构中包括这两个组件,例如us FrontComponent>BackComponent,以便在不计算位置的情况下使用EventFilter。但是,由于上下文不改变层次结构,这是最好的解决方案。正确的方法是在层次结构中包括两个组件,例如us FrontComponent>BackComponent,以便在不计算位置的情况下使用EventFilter
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class Main extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Rectangle backComponent = new Rectangle(200, 200, Color.ORANGE);
        Rectangle frontComponent = new Rectangle(180, 180, Color.GREY);

        StackPane root = new StackPane(backComponent, frontComponent);

        frontComponent.setOnMouseClicked((mouseClicked) -> {
            if (mouseClicked.getButton() == MouseButton.SECONDARY) {
                boolean isInBackComponent = backComponent.contains(
                        backComponent.sceneToLocal(
                                mouseClicked.getSceneX(), mouseClicked.getSceneY()
                        )
                );

                if (isInBackComponent) {
                    backComponent.fireEvent(mouseClicked);
                    return;
                }
            }

            if (mouseClicked.getButton() == MouseButton.PRIMARY) {
                System.out.println("FrontComponent left click");
            }
        });

        backComponent.setOnMouseClicked((mouseClicked) -> {
            if (mouseClicked.getButton() == MouseButton.SECONDARY) {
                System.out.println("BackComponent right click");
            }
        });

        stage.setScene(new Scene(root, 500, 500));
        stage.show();
    }

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