javafxscenebuildergluon

JavaFX Menu Bar Steals Focus


I have an app where, when the user is typing in a text input, typing a normal letter causes the menu bar to activate (drop down its sub-menu) instead of filling the input as it should.

The easiest way to see this issue is to grab SceneBuilder, drop down a panel and an area chart and start typing into the Title field. I typed "The", and the "e" caused the "Edit" menu to drop down as shown.

enter image description here

It doesn't always happen, and it goes away if you Alt your way out of the menu bar, so I presume it's some kind of MenuBar state issue.

I'm wondering how to make the MenuBar respect the input's sovereignty and if there is a fix, why does it behave this way under SceneBuilder?

Currently using SceneBuilder v18 on Windows, though I've seen this going back to v12 or v13. Always on Windows.

EDIT: Going on @Slaw's suggestion, I think the real issue is that once the Menu bar is activated with an Alt, it never deactivates until you press Alt again. So, you can hit Alt, give various inputs the focus and type into them, drag and drop new controls...basically do anything all while the Menu Bar is waiting to eat the keystroke.

The desired behavior is for either the menu bar to only activate WHILE Alt is being pressed or for it to give up the focus if the next key doesn't activate. Not to lie in wait, letting all keystrokes pass by until it can pounce on one.


Solution

  • Note that this bug was resolved in JavaFX 21.


    For older version of JavaFX:

    When the stage regains focus, send an Esc key press event to the menu bar. You'll need to change up the variable names in the code below to match those from your own code base.

    // After the app loses focus, when the user switches back using Alt+Tab,
    // the menu is engaged on Windows. Simulate an ESC keypress to the menu
    // to disable the menu, giving focus back to the application proper.
    //
    // JavaFX Bug: https://bugs.openjdk.java.net/browse/JDK-8090647
    stage.focusedProperty().addListener( ( c, lost, found ) -> {
      if( found ) {
        mMainScene.getMenuBar().fireEvent( keyDown( ESCAPE, false ) );
      }
    } );
    
    public static Event keyDown( final KeyCode code, final boolean shift ) {
      return keyEvent( KEY_PRESSED, code, shift );
    }
    
    private static Event keyEvent(
      final EventType<KeyEvent> type, final KeyCode code, final boolean shift ) {
      return new KeyEvent(
        type, "", "", code, shift, false, false, false
      );
    }
    

    Tested on Windows 10, Java 19, and JavaFX 19.