When looking at the code for Scene#setOnKeyPressed, I noticed that it calls Scene#setEventHandler.  This is documented as:

    /**
     * Sets the handler to use for this event type. There can only be one such
     * handler specified at a time. This handler is guaranteed to be called
     * first. This is used for registering the user-defined onFoo event
     * handlers.
     *
     * @param <T> the specific event class of the handler
     * @param eventType the event type to associate with the given eventHandler
     * @param eventHandler the handler to register, or null to unregister
     * @throws NullPointerException if the event type is null
     */
    protected final <T extends Event> void setEventHandler(
            final EventType<T> eventType,
            final EventHandler<? super T> eventHandler) {

Note that it specifically says "This handler is guaranteed to be called first."

This function eventualy calls CompositeEventHandler#setEventHandler.  This class tracks a chain of handlers, and reserves a special spot for a single special "eventHandler".  Yet, in its dispatchBubblingEvent method, it clearly calls the "special" handler LAST... see below:

    public void dispatchBubblingEvent(final Event event) {
        final T specificEvent = (T) event;

        EventProcessorRecord<T> record = firstRecord;
        while (record != null) {
            if (record.isDisconnected()) {
                remove(record);
            } else {
                record.handleBubblingEvent(specificEvent);
            }
            record = record.nextRecord;
        }

        if (eventHandler != null) {
            eventHandler.handle(specificEvent);
        }
    }

I've confirmed this with this small program (order of calls doesn't make a difference):

    public static class App extends Application {
      @Override
      public void start(Stage primaryStage) {
        Button button1 = new Button("111");

        HBox hBox = new HBox();
        hBox.getChildren().addAll(button1);
        Scene scene = new Scene(hBox, 300, 300);

        scene.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
          System.out.println("KeyPressedHandler " + e);
        });
        scene.setOnKeyPressed(e -> {
          System.out.println("Main " + e);
          e.consume();
        });

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

Which outputs the events not in the order documented:

KeyPressedHandler KeyEvent [source = javafx.scene.Scene@36dbf594, target = Button@5dd3d27e[styleClass=button]'111', eventType = KEY_PRESSED, consumed = false, character =  , text = f, code = F] Main KeyEvent [source = javafx.scene.Scene@36dbf594, target = Button@5dd3d27e[styleClass=button]'111', eventType = KEY_PRESSED, consumed = false, character =  , text = f, code = F]

--John

Reply via email to