当前位置: 首页 > 知识库问答 >
问题:

如何禁用JavaFX菜单栏的助记符?

宋斌
2023-03-14

在我的阶段,我像往常一样在程序的顶部插入了一个菜单栏。我想在stage中的另一个上下文中为ALT键(连同箭头键)提供一些逻辑。但每次按下ALT和箭头时,我也会无意中浏览菜单栏的菜单。

我想避免这种情况,或者更好地完全禁用这种助记行为。将所有菜单的助记词解析属性设置为false失败了。我也尝试了这种方法,但没有成功:

menubar.addEventFilter(KeyEvent.ANY, e -> e.consume());

共有2个答案

阚英武
2023-03-14

或者您可以重写MenuBar皮肤。Javafx已经做出选择(或者这是一个错误?),当按下ALT键时,焦点将被赋予MenuBar,而不是释放,这是Eclipse、Netbean、......更重要的是,当按下或释放ALT_GRAPH键时,焦点不应被赋予MenuBar。

这是我提出的补丁。请注意,只有第一个差异是相关的,最后一个差异只是为了在无法访问代码时编译代码。基本上,我已经将“firstMenuRunnable”拆分为3个函数

>

  • 仅当按下F10键时才使用FirstMenuRunTable

    当菜单栏有焦点且按下ALT键时,使用DeclesionKeyPressed

    当菜单栏没有焦点且ALT键被释放时,使用focusOnFirstMenuOnKeyReleased

    因此,可以使用标准行为,允许加速器使用ALT键,而无需菜单栏获取焦点。

        --- 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's 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's 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();
                         }
                     });
    

    下面是我的菜单栏的完整代码:

    /*
     * 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) {
    
            };
        }
    
    }
    

  • 华心思
    2023-03-14

    当按下ALT时,第一个菜单获得焦点,当菜单具有焦点时,无论是否按下ALT,箭头键都会在它们之间导航。因此,为了防止这种行为,您需要防止第一个菜单在按下ALT时获得焦点。

    查看MenuBarSkin类的构造函数源代码,我们可以找到解决方案:

    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.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent event) {
            // your desired behavior
            if(event.isAltDown())
                event.consume();
        }
    });
    
     类似资料:
    • 因此,我仍然有点了解JavaFX,我能够禁止在文本框中输入文本,但我不知道如何防止右键单击时出现上下文菜单。有人知道如何防止右键单击时弹出默认上下文菜单吗?`

    • 我正在使用MasterDetailPage并在其中使用动作条。我已经禁用和隐藏的标志,图标和后退按钮的动作条。但当我尝试从左到右从左侧滑动时,一个空白菜单列表打开。我不知道为什么会这样。我如何禁用操作条的这个。我不想要菜单列表这就是为什么我禁用后退按钮,图标。当我从左到右滑动时,我如何禁用这个从左到右滑动的菜单?

    • 如何从操作栏禁用“选项”菜单项? 我做了我自己的自定义栏,用于显示*. png标志,但我不想显示选项菜单的三个点按钮。 我试图找到一些解决办法,但没有任何效果。

    • 我想在Stage中添加一个JavaFX菜单栏,但是让它使用Mac的系统菜单栏。 我的问题是使用: 不起作用。我认为问题在于我的主要方法不是JavaFX应用程序的一部分。我的主要方法如下所示: SURPG_Mac.class和SURPG_Main.class是扩展 JavaFX 应用程序的类。 我有另一个设置GUI的类,一个带有BorderPane的阶段。我有另一个具有公共静态方法的类,可以调用它来

    • 感谢阅读。我试图用css编辑一个菜单栏,但是菜单项没有改变。 我意识到菜单栏的部分是:菜单栏,菜单,菜单项,但最后一个不能正常工作。帮助 我正在使用场景生成器。

    • 当助记字符添加到菜单文本中时,我们必须按Alt键才能显示助记下划线。如何让菜单助记下划线始终出现在我们按Alt之前?