JDK-8229467 : Fired ActionEvent not consumed if (unrelated!) EventFilter in dispatch chain
  • Type: Bug
  • Component: javafx
  • Sub-Component: controls
  • Affected Version: jfx11
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2019-08-13
  • Updated: 2024-08-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Relates :  
Relates :  
Description
The problem arises when we have some entity that fires an actionEvent and wants to fork further processing based on the consumed flag of the event. If the action that it fires is not consumed, further processing is incorrect.

The example demonstrates this on a textField:
- as sender, it has a keyPressed handler, fires an actionEvent and prints out the consumed flag
- as receiver it has an action handler that consumes the event

To reproduce:
- compile and run the example as-is
- expected and actual: the fired event is consumed
A:
- uncomment the lines that add an eventFilter to the stage
- expected: fired event is consumed
- actual: fired event it not consumed
B:
- also uncomment the line that removes the eventFilter immediately
- expected: fired event is consumed
- actual: fired event it not consumed

Technically, the reason is that the fired and the received actionEvent are different instances if an eventFilter (for eventType action or above) is present in the dispatch chain: EventHandlerManager.dispatchCapturingEvent dispatches a copy of the fired events, the receiver consumes the copy which - obviously - has no effect on the originally fired action. 

Not entirely certain how to fix that
A: as of JDK-8091151, the event dispatch across the hierarchy might have to be handled differently for some - here action - events 
B: due to JDK-8092352, the event is copied even if an eventFilter is removed again - the compositeEventHandler only nulls its records (and handler) and eventHandlerManager doesn't check if there are any filters:

    private Event dispatchCapturingEvent(
            final EventType<? extends Event> handlerType, Event event) {
        final CompositeEventHandler<? extends Event> compositeEventHandler =
                eventHandlerMap.get(handlerType);

        if (compositeEventHandler != null) {
            // TODO: skip when no filters are registered in the
            //       CompositeEventHandler (RT-23952) now JDK-8092352
            event = fixEventSource(event, eventSource);
            compositeEventHandler.dispatchCapturingEvent(event);
        }

        return event;
    }

P3 because there are some bugs around textField with/out formatter where the incorrect consumed flag leads to problems, f.i. JDK-8207774 and its related issues

The example:

public class ActionDispatchBug extends Application {
    
    public Parent createContent() {
        TextField field = new TextField();
        // some handler to fire an actionEvent
        field.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
            if (e.getCode() == KeyCode.A) {
                ActionEvent action = new ActionEvent(field, field);
                field.fireEvent(action);
                LOG.info("action fired "  + action.isConsumed() + " @" + action.hashCode());
            }
        });
        // another handler to consume the fired action
        field.addEventHandler(ActionEvent.ACTION, action -> {
            action.consume();
            LOG.info("action consumed: " + " @" + action.hashCode() );
        });
        
        VBox actionUI = new VBox(field);
        return actionUI;
    }

    @Override
    public void start(Stage stage) throws Exception {
        Scene scene = new Scene(createContent());
        stage.setScene(scene);
        
        // add/remove an eventFilter 
//        EventHandler filter = e -> {};
//        stage.addEventFilter(EventType.ROOT, filter);
//        stage.removeEventFilter(EventType.ROOT, filter);
        
        //stage.setTitle(FXUtils.version());
        stage.setX(100);
        stage.show();
    }

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

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(ActionDispatchBug.class.getName());

}

Comments
SOF is weird: notice -1 rating on the question.
07-08-2024

see also https://stackoverflow.com/q/57428846/203657
13-08-2019