How to disable mnemonics for JavaFX MenuBar?

In my scene, I inserted a menu bar at the top, as usual for programs. I want to give the ALT key (along with the arrows) some logic in a different context on the scene. But every time I press ALT and the arrows, I inadvertently navigate the menu as well.

I want to avoid this or it is better to completely disable this mnemonic behavior. Failed to set mnemonicParsing properties for all menus to false. I also tried this approach without success:

menubar.addEventFilter(KeyEvent.ANY, e -> e.consume());
+4
source share
2 answers

ALT, , , , ALT . , , ALT.

MenuBarSkin class, :

public MenuBarSkin(final MenuBar control) {
    ...
    Utils.executeOnceWhenPropertyIsNonNull(control.sceneProperty(), (Scene scene) -> {
        scene.getAccelerators().put(acceleratorKeyCombo, firstMenuRunnable);

        // put focus on the first menu when the alt key is pressed
        scene.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
            if (e.isAltDown()  && !e.isConsumed()) {
                firstMenuRunnable.run();
            }
        });
    });
    ...
}

:

, , , ALT , EventHandler scene not menubar:

scene.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
    @Override
    public void handle(KeyEvent event) {
        // your desired behavior
        if(event.isAltDown())
            event.consume();
    }
});
+3

MenuBar. Javafx ( ?), MenuBar, ALT , , Eclipse, Netbeans,.... ALT_GRAPH, MenuBar.

, . , , , . , "firstMenuRunnable" 3

  • firstMenuRunnable F10

  • deselectOnKeyPressed , menuBar , ALT -

  • focusOnFirstMenuOnKeyReleased , menuBar ALT

, , ALT- MenuBar.

    --- com/sun/javafx/scene/control/skin/MenuBarSkin.java in C:\Program Files (x86)\Java\jdk1.8.0_131\javafx-src.zip
    +++ C:\Users\daniel\dev\xxx\Layout\src\com\stimulus\control\MenuBarSkin.java     
@@ -372,12 +491,21 @@
             scene.getAccelerators().put(acceleratorKeyCombo, firstMenuRunnable);

             // put focus on the first menu when the alt key is pressed
+            scene.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
+                altDown = false;
+            });
             scene.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
-                if (e.isAltDown()  && !e.isConsumed()) {
-                    firstMenuRunnable.run();
+                if (e.isAltDown() && !e.isConsumed() && e.getCode().equals(KeyCode.ALT)) {
+                    deselectMenusOnKeyPressed.run();
+                    altDown = true;
                 }
             });
+            scene.addEventHandler(KeyEvent.KEY_RELEASED, e -> {
+                if (altDown) {
+                    focusOnFirstMenuOnKeyReleased.run();
+                }
         });
+        });

         ParentTraversalEngine engine = new ParentTraversalEngine(getSkinnable());
         engine.addTraverseListener(this);
    @@ -434,7 +453,50 @@
                 }
             };

    +    private boolean menuDeselectedOnKeyPressed = false;

    +    Runnable deselectMenusOnKeyPressed = new Runnable() {
    +        public void run() {
    +            /*
    +             ** check that this menubar container has contents,
    +             ** and that the first item is a MenuButton....
    +             ** otherwise the transfer is off!
    +             */
    +            menuDeselectedOnKeyPressed = false;
    +            if (container.getChildren().size() > 0) {
    +                if (container.getChildren().get(0) instanceof MenuButton) {
    +//                        container.getChildren().get(0).requestFocus();
    +                    if (focusedMenuIndex >= 0) {
    +                        unSelectMenus();
    +                        menuDeselectedOnKeyPressed = true;
    +                    }
    +                }
    +            }
    +        }
    +    };
    +    Runnable focusOnFirstMenuOnKeyReleased = new Runnable() {
    +        public void run() {
    +            /*
    +             ** check that this menubar container has contents,
    +             ** and that the first item is a MenuButton....
    +             ** otherwise the transfer is off!
    +             */
    +            if (container.getChildren().size() > 0) {
    +                if (container.getChildren().get(0) instanceof MenuButton) {
    +//                        container.getChildren().get(0).requestFocus();
    +                    if (focusedMenuIndex == -1 && !menuDeselectedOnKeyPressed) {
    +                        unSelectMenus();
    +                        menuModeStart(0);
    +                        openMenuButton = ((MenuBarButton) container.getChildren().get(0));
    +                        openMenu = getSkinnable().getMenus().get(0);
    +                        openMenuButton.setHover();
    +                    }
    +                }
    +            }
    +        }
    +    };
    +
         private boolean pendingDismiss = false;

         // For testing purpose only.
    @@ -650,9 +712,23 @@
                 menuButton.textProperty().bind(menu.textProperty());
                 menuButton.graphicProperty().bind(menu.graphicProperty());
                 menuButton.styleProperty().bind(menu.styleProperty());
    +            // patch because MenuButtonSkin.AUTOHIDE is private
    +            final String AUTOHIDE;
    +            {
    +                try {
    +                    Class<?> clazz = MenuButtonSkin.class;
    +//                    System.out.println("fields = " + Arrays.asList(clazz.getDeclaredFields()).toString());
    +                    Field field = clazz.getDeclaredField("AUTOHIDE");
    +                    field.setAccessible(true);
    +                    AUTOHIDE = (String) field.get(this);
    +                    field.setAccessible(false);
    +                } catch (NoSuchFieldException | SecurityException | IllegalAccessException | IllegalArgumentException ex) {
    +                    throw new UnsupportedOperationException(ex);
    +                }
    +            }
                 menuButton.getProperties().addListener((MapChangeListener<Object, Object>) c -> {
    -                 if (c.wasAdded() && MenuButtonSkin.AUTOHIDE.equals(c.getKey())) {
    -                    menuButton.getProperties().remove(MenuButtonSkin.AUTOHIDE);
    +                if (c.wasAdded() && AUTOHIDE.equals(c.getKey())) {
    +                    menuButton.getProperties().remove(AUTOHIDE);
                         menu.hide();
                     }
                 });

MenuBar:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.stimulus.control;

import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.Skin;

/**
 *
 * @author daniel
 */
public class CustomMenuBar extends MenuBar {

    public CustomMenuBar() {
    }

    public CustomMenuBar(Menu... menus) {
        super(menus);
    }

    @Override
    protected Skin<?> createDefaultSkin() {
        return new MenuBarSkin(this) {

        };
    }

}
0

All Articles