JDK-8234247 : ComboBox: cancel button must not be triggered if escape is consumed by combo handler
  • Type: Bug
  • Component: javafx
  • Sub-Component: controls
  • Affected Version: openjfx11
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2019-11-15
  • Updated: 2021-12-06
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 :  
Description
To reproduce, run the example below, focus one of the combo, press escape

expected: message from combo handler printed
actual: message from cancel button is printed before message from combo handler

The bug is similar to JDK-8207759 (there reported against ENTER and TextField), with the same underlying reason: ComboBoxBaseBehavior has a keyMapping for ESCAPE which forwards the event to the combo's parent if interpreted as not used. This manual firing of the received keyEvent wrecks the event deliverance sequence such that handlers  in the parent hierarchy see the event before the consuming singleton handler of the combo.

The fix is basically the same: in ComboBoxBaseBehavior, replace the manual forwarding by letting the event travel "naturally" up the chain. 

The example:

public class ComboCancelButton extends Application {

    private Parent createContent() {
        ObservableList<String> data= FXCollections.observableArrayList("one", "two");
        ComboBox<String> editable = new ComboBox<>(data);
        editable.setEditable(true);
        EventHandler<KeyEvent> consumer = e -> {
            if (e.getCode() == ESCAPE) {
                System.out.println("consuming escape");
                e.consume();
            }
        };
        editable.setOnKeyPressed(consumer);
        
        ComboBox<String> notEditable = new ComboBox<>(data);
        notEditable.setOnKeyPressed(consumer);
        
        Button cancel = new Button("Cancel");
        cancel.setCancelButton(true);
        cancel.setOnAction(a -> System.out.println("cancel triggered"));
        
        VBox content=  new VBox(10, editable, notEditable, cancel);
        return content;
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent()));
        stage.show();
    }

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

}

Comments
didn't look into this for a while - so marking as stopped for now ;)
06-12-2021

now really working on it :) The fix is - remove the esc mapping from ComboBoxBaseBehavior completely, including the private cancel method: it does nothing except second guessing editor's behavior if it has a textFormatter - change key eventFilter in ComboBoxPopupControl to fire the escape down into the editor, just like any other key Added tests: - added XXDefaultCancelButtonTest for all concrete subs of ComboboxBase - added test in ComboBoxSpecialKey to guarantee correct cancel in editor with textFormatter the former bunch fails (in regard to Esc) before the fix and passes after, the latter passes for before and after
17-12-2019

actually, it's ready - only blocked by review/integration of JDK-8207759 (the fix to that issue itself makes no difference here, but tests added for that are extended here :)
21-11-2019