如何将ScrollPane事件KEY_PRESSED,KeyCode.LEFT传递给父窗格?

时间:2018-02-10 11:11:00

标签: javafx javafx-2

我有一个带有单个子项的StackPane - ScrollPane。我试图在StackPane上处理KEY_PRESSED,KeyCode.LEFT(只是一个例子,我想处理每个箭头键)事件。 因为我担心ScrollPane会消耗特定事件。我想阻止这种情况,但找不到任何合理的方法。

2 个答案:

答案 0 :(得分:1)

import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventDispatcher;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class ScrollPaneDispatcherApp extends Application {

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

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

        StackPane stackPane = new StackPane();
        stackPane.setStyle("-fx-backgound-color: red");

        ScrollPane scrollPane = new ScrollPane();
        scrollPane.setStyle("-fx-background-color: yellow");

        stackPane.getChildren().add(scrollPane);

        Scene scene = new Scene(stackPane);
        stage.setScene(scene);
        stage.show();

        scrollPane.requestFocus();

        EventDispatcher sceneEventDispatcher = scene.getEventDispatcher();
        EventDispatcher stackPaneEventDispatcher = stackPane.getEventDispatcher();
        EventDispatcher scrollPaneEventDispatcher = scrollPane.getEventDispatcher();

        scene.setEventDispatcher((event, tail) -> {
            if (KeyEvent.ANY.equals(event.getEventType().getSuperType())) {
                System.out.println("DISPATCH\tScene\t\tevent=" + event.getEventType());
            }
            return sceneEventDispatcher.dispatchEvent(event, tail);
        });

        stackPane.setEventDispatcher((event, tail) -> {
            if (KeyEvent.ANY.equals(event.getEventType().getSuperType())) {
                System.out.println("DISPATCH\tStackPane\tevent=" + event.getEventType());
            }
            return stackPaneEventDispatcher.dispatchEvent(event, tail);
        });

        scrollPane.setEventDispatcher((event, tail) -> {
            if (KeyEvent.ANY.equals(event.getEventType().getSuperType())) {
                System.out.println("DISPATCH\tScrollPane\tevent=" + event.getEventType());
            }
            Event eventToDispatch = scrollPaneEventDispatcher.dispatchEvent(event, tail);
            if (KeyEvent.KEY_PRESSED.equals(event.getEventType())) {
                if (KeyCode.LEFT.equals(((KeyEvent) event).getCode()) || KeyCode.RIGHT.equals(((KeyEvent) event).getCode())) {
                    if (eventToDispatch == null) {
                        return event;
                    }
                }
            }
            return eventToDispatch;
        });

        scene.addEventFilter(KeyEvent.ANY,
                event -> System.out.println("FILTER\t\tScene\t\tevent=" + event.getEventType()));
        stackPane.addEventFilter(KeyEvent.ANY,
                event -> System.out.println("FILTER\t\tStackPane\tevent=" + event.getEventType()));
        scrollPane.addEventFilter(KeyEvent.ANY,
                event -> System.out.println("FILTER\t\tScrollPane\tevent=" + event.getEventType()));

        scene.addEventHandler(KeyEvent.ANY,
                event -> System.out.println("HANDLER\t\tScene\t\tevent=" + event.getEventType()));
        stackPane.addEventHandler(KeyEvent.ANY,
                event -> System.out.println("HANDLER\t\tStackPane\tevent=" + event.getEventType()));
        scrollPane.addEventHandler(KeyEvent.ANY,
                event -> System.out.println("HANDLER\t\tScrollPane\tevent=" + event.getEventType()));
    }
}

建议的解决方案会覆盖ScrollPane的LEFT,右箭头KEY_PRESSED事件消耗行为。线索是ScrollPane的新EventDispatcher。其余代码仅用于调试目的。

答案 1 :(得分:0)

默认情况下,ScrollPane将使用按键事件而StackPane不会。

如果要使用父窗格事件处理程序拦截按键,则应使用事件过滤器(https://docs.oracle.com/javafx/2/events/filters.htm)来执行此操作(在捕获阶段而不是冒泡阶段拦截事件)

如果您需要了解捕获与冒泡概念,请阅读事件处理(https://docs.oracle.com/javafx/2/events/processing.htm)。

来自docs.oracle.com/javafx/2/events/filters.htm:事件过滤器使父节点能够为其子节点提供常见处理或拦截事件并阻止子节点对事件进行操作