0

in JAVAFX, I am using shortcut by using setMnemonicParsing(true)

code which is from googling is below

VBox mainLayout = new VBox();  

MenuBar menuBar = new MenuBar();  
Menu menu1 = new Menu("_File");  
menu1.setMnemonicParsing(true);  
menu1.getItems().addAll(new MenuItem("Menu 1"), new MenuItem("Menu 2"));  

Menu menu2 = new Menu("_Other");  
menu2.setMnemonicParsing(true);  
menu2.getItems().addAll(new MenuItem("Other 1"), new MenuItem("Other 2"));  

menuBar.getMenus().setAll(menu1, menu2);  

mainLayout.getChildren().setAll(menuBar);  

Scene scene = new Scene(mainLayout, 300, 100);  

stage.setTitle("Demo of mnemonic");  
stage.setScene(scene);  
stage.sizeToScene();  
stage.show();   

here is the steps (window platform)

  1. press Alt key
  2. can see mnemonic letter
  3. press F key
  4. drop down menu and get focus
  5. press arrow(->) key
  6. error like below

java.lang.NullPointerException at com.sun.javafx.scene.control.skin.MenuBarSkin.isMenuEmpty(MenuBarSkin.java:728) at com.sun.javafx.scene.control.skin.MenuBarSkin.showNextMenu(MenuBarSkin.java:781)

but when I click the the Menubar with mouse, it doesn't happen.

any solution?

  • `f` isn't a mnemonic in your code. Can you edit the question to include an [sscce](http://sscce.org)? Please also include information on your OS and Java versions. – jewelsea Oct 15 '13 at 03:16
  • Tested on Win7 with JavaFX 2.2. It is definitely a bug, you can file it at Jira. – Uluk Biy Oct 15 '13 at 11:57

3 Answers3

1

Gotta agree with Jamal here, the burden falls to us lowly programmers to fix it until Oracle fixes it. I have an expansion on his fix that should, perhaps with just one or two modifications, work for an arbitrary menu.

    stage.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {

        @Override
        public void handle(KeyEvent event) {
            final int size = menuBar.getMenus().size();

            boolean showing = false;
            int index = 0;
            for(index = 0; index < menuBar.getMenus().size(); ++index) {
                if(menuBar.getMenus().get(index).isShowing()) {
                    showing = true;
                    break;
                }
            }
            index = (index < 0 ? menuBar.getMenus().size() + index : index) % size;

            if(showing) {
                Menu menu1 = null, menu2 = null;
                menu1 = menuBar.getMenus().get(index);

                if(event.getCode() == KeyCode.RIGHT) {

                    event.consume(); // remove event for next step
                    menu2 = menuBar.getMenus().get((index + 1) % size);

                    menu1.hide();
                    menu2.show();
                }
                else if(event.getCode() == KeyCode.LEFT) {

                    event.consume(); // remove event for next step

                    menu1 = menuBar.getMenus().get(index);
                    menu2 = menuBar.getMenus().get((index - 1) < 0 ? size + (index - 1) : (index - 1));

                    menu1.hide();
                    menu2.show();
                }
            }
        }
    });

Personally, I think that bug fixes should be kept as tight as possible, and this takes an arbitrary menu bar size. So, if, like me, you're running into this bug with an otherwise perfectly functional JavaFX program that changes its menus dynamically (and at the drop of a hat), it might be useful.

Michael Oberlin
  • 479
  • 4
  • 4
0

Self workaround solution below.

I found out that it's a Java FX 2.2 bug on Windows 7.

Steps::

  1. add keyevent to the stage
  2. consume() event when getting a RIGHT; LEFT event on menu focused.
  3. implement yourself

stage.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {

    @Override
    public void handle(KeyEvent event) {
        if(menu1 .isShowing() || menu2 .isShowing() || menu2 .isShowing()) {

            if(event.getCode() == KeyCode.RIGHT) {

                log.debug("right");
                event.consume(); // remove event for next step

                if(menu1.isShowing()) {
                    menu1.hide();
                    menu2.show();
                }
                else if(menu2.isShowing()) {
                    menu2.hide();
                    menu3.show();
                }
                else if(menu3.isShowing()) {
                    menu3.hide();
                    menu1.show();
                }
            }
            else if(event.getCode() == KeyCode.LEFT) {

                log.debug("left");
                event.consume();

                if(menu1.isShowing()) {
                    menu1.hide();
                    menu3.show();
                }
                else if(menu2.isShowing()) {
                    menu2.hide();
                    menu1.show();
                }
                else if(menu3.isShowing()) {
                    menu3.hide();
                    menu2.show();
                }
            }
        }
    }
});
Jamal
  • 763
  • 7
  • 22
  • 32
0

I found that the only reliable way to show the menu and support navigation without getting a bunch of null pointer exceptions elsewhere and style changes is to simulate actual user event flow:

MenuBar menuBar; // given a menuBar not null and not empty
KeyEvent evt; // and some event hook not currently consumed

boolean handled = true;

HANDLED:
do
{
do
{
    // do your handling

    Node n = menuBar;
    try
    {
        while (!(n instanceof MenuButton) && (n instanceof Parent))
        {
            n = ((Parent)n).getChildrenUnmodifiable().get(0);
        }
    }
    catch (IndexOutOfBoundsException e)
    {
        // This should not be possible if there exists menu items in the menu bar...
        break;
    }

    if (!(n instanceof MenuButton))
    {
        // This should not be possible if there exists menu items in the menu bar...
        break;
    }


    // avoid null exceptions in glass pane on immediate click up/down
    // and PREVENT unwanted style changes in de-selected state display. 
    EventHandler<? super MouseEvent> mouseHandler = n.getOnMouseEntered();
    if (mouseHandler != null)
    {
        mouseHandler.handle(null);
    }

    // perform the "focusing and invocation" of the menu button
    Event.fireEvent(n, MouseEvent.impl_mouseEvent(0, 0, 0, 0, MouseButton.PRIMARY, 1, false, false, false, false, false, true, false, false, false, MouseEvent.MOUSE_PRESSED));

    // null out the state machine where the mouse is concerned
    // prevent null exceptions in glasspane handlers in subsequent navigation movements
    Event.fireEvent(n, MouseEvent.impl_mouseEvent(0, 0, 0, 0, MouseButton.PRIMARY, 0, false, false, false, false, false, false, false, false, false, MouseEvent.MOUSE_RELEASED));

    break HANDLED;
} while (false);
// non-standard termination
handled = false;
} while (false);

if (handled)
{
    evt.consume();
}
user3200607
  • 107
  • 1
  • 2