Implementation not following documentation regarding when event handler gets called

John Hendrikx john.hendrikx at gmail.com
Sun May 28 10:02:17 UTC 2023


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 at 36dbf594, target 
= Button at 5dd3d27e[styleClass=button]'111', eventType = KEY_PRESSED, 
consumed = false, character =  , text = f, code = F]
Main KeyEvent [source = javafx.scene.Scene at 36dbf594, target = 
Button at 5dd3d27e[styleClass=button]'111', eventType = KEY_PRESSED, 
consumed = false, character =  , text = f, code = F]

--John



More information about the openjfx-dev mailing list