如何将鼠标事件委托给JavaFX中的所有底层重叠窗格? [英] How to delegate mouse events to all underlying overlapped panes in JavaFX?

查看:163
本文介绍了如何将鼠标事件委托给JavaFX中的所有底层重叠窗格?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些顶部装饰窗格,我想处理/预处理鼠标事件,但不应该使用它们,即所有重叠的窗格应该像装饰窗格没有重叠一样工作。

I have some top decoration pane, which I want to process/preprocess mouse events, but which should not consume them, i.e. all overlapped panes should work as if they were not overlapped by decoration pane.

怎么做?我失败了几次尝试。

How to do this? I failed with several tries.

下面是一个包含3个窗格的代码。绿色的是装饰。任务是使其对鼠标事件透明。黄色和蓝色窗格是工人窗格。它们应该像绿色窗格没有重叠一样工作。

Below is a code with 3 panes. Green one is "decorating". The task is to make it transparent to mouse events. Yellow and blue panes are worker panes. They should work as if they were not overlapped by green pane.

但绿色窗格应该会收到鼠标事件。

But green pane should receive mouse events nevertheless.

注释行表示我尝试的内容,评论说出错了:

Commented lines indicate what I tries and comments say what appeared wrong:

import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

/**
 * Created by dims on 13.10.2016.
 */
public class DelegateEventsToOverlappedNodes extends Application{


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

      StackPane root = new StackPane();
      root.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)));


      AnchorPane yellowPane = new AnchorPane();
      yellowPane.setBackground(new Background(new BackgroundFill(Color.YELLOW, CornerRadii.EMPTY, Insets.EMPTY)));
      yellowPane.setOnMouseClicked(new EventHandler<MouseEvent>() {
         @Override
         public void handle(MouseEvent event) {
            System.out.println("yellowPane clicked");
         }
      });


      root.getChildren().add(yellowPane);


      Pane bluePane = new Pane();
      bluePane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
      bluePane.setOnMouseClicked(new EventHandler<MouseEvent>() {
         @Override
         public void handle(MouseEvent event) {
            System.out.println("bluePane clicked");
         }
      });

      AnchorPane.setLeftAnchor(bluePane, 200.);
      AnchorPane.setRightAnchor(bluePane, 200.);
      AnchorPane.setTopAnchor(bluePane, 200.);
      AnchorPane.setBottomAnchor(bluePane, 200.);


      yellowPane.getChildren().add(bluePane);




      AnchorPane greenPane = new AnchorPane();
      greenPane.setBackground(new Background(new BackgroundFill(Color.rgb(0, 255, 0, 0.9), CornerRadii.EMPTY, Insets.EMPTY)));
      greenPane.setOnMouseClicked(new EventHandler<MouseEvent>() {
         @Override
         public void handle(MouseEvent event) {
            System.out.println("greenPane clicked");
         }
      });


      // greenPane.setVisible(false); // green pane invisible at all

      // greenPane.setMouseTransparent(true); // green clicked doesn't occur

      // greenPane.addEventHandler(Event.ANY, event -> yellowPane.fireEvent(event)); // works for yellow pane, but not for blue sub pane



      root.getChildren().add(greenPane);


      Scene scene = new Scene(root, 800, 600);

      primaryStage.setScene(scene);
      primaryStage.setTitle("DelegateEventsToOverlappedNodes");
      primaryStage.show();

   }

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


推荐答案

你可以再次设置 greenPane 鼠标透明并将事件过滤器添加到 root 以预处理鼠标事件:

You could set greenPane mouse transparent again and add an event filter to root to preprocess the mouse events here:

greenPane.setMouseTransparent(true);
root.addEventFilter(MouseEvent.MOUSE_CLICKED, event -> System.out.println(event));

在事件处理的事件捕获阶段过滤接收事件,而在事件冒泡阶段触发处理程序。您也可以使用事件处理程序,但我认为在这种情况下过滤器更具惯用性(阅读更多这里)。

Filters receive events during the event capturing phase of event processing, whereas handlers are triggered during the event bubbling phase. You could also use an event handler, but I think a filter is more idiomatic in this case (read more here).

您的代码:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class DelegateEventsToOverlappedNodes extends Application {

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        // Yellow pane.
        AnchorPane yellowPane = new AnchorPane();
        yellowPane.setBackground(new Background(new BackgroundFill(Color.YELLOW, CornerRadii.EMPTY, Insets.EMPTY)));
        yellowPane.setOnMouseClicked(event -> System.out.println("yellowPane clicked"));

        // Blue pane.
        AnchorPane bluePane = new AnchorPane();
        bluePane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
        bluePane.setOnMouseClicked(event -> System.out.println("bluePane clicked"));
        AnchorPane.setLeftAnchor(bluePane, 200.0);
        AnchorPane.setRightAnchor(bluePane, 200.0);
        AnchorPane.setTopAnchor(bluePane, 200.0);
        AnchorPane.setBottomAnchor(bluePane, 200.0);

        // Green pane.
        AnchorPane greenPane = new AnchorPane();
        greenPane.setBackground(new Background(new BackgroundFill(Color.rgb(0, 255, 0, 0.9), CornerRadii.EMPTY, Insets.EMPTY)));
        greenPane.setMouseTransparent(true);

        // Root pane.
        StackPane rootPane = new StackPane();
        rootPane.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)));
        rootPane.addEventFilter(MouseEvent.MOUSE_CLICKED, event -> System.out.println(event));

        // Layout and scene.
        yellowPane.getChildren().add(bluePane);
        rootPane.getChildren().addAll(yellowPane, greenPane);

        primaryStage.setScene(new Scene(rootPane, 800.0, 600.0));
        primaryStage.setTitle("DelegateEventsToOverlappedNodes");
        primaryStage.show();
    }

}

如果你创建了 greenPane 仅用于预处理事件,不再需要它。

If you created greenPane only to preprocess events, there's no need for it anymore.

这篇关于如何将鼠标事件委托给JavaFX中的所有底层重叠窗格?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆