javaswingjavafxacceleratorkey

Accelerator commands not working when focus lost


I have the following swing application,

which has a customized JMenuBar.

The code goes below,

public class MenuBarTest {
    public static void main(String[] args) {
        new JFXPanel();
        final JFrame frame = new JFrame();
        frame.setLayout(new BorderLayout());
        frame.getContentPane().add(new JTextField("Testing", JLabel.CENTER),
                BorderLayout.CENTER);
        frame.setJMenuBar(new DummyMenuBar());
        frame.setSize(300, 300);
        frame.setVisible(true);
    }
}

DummyMenuBar.java

public class DummyMenuBar extends JMenuBar {
private MenuBar menuBar;
private MenuItem menuItem;

public DummyMenuBar() {
    try {
        addToScene();
    } catch (Exception e) {
    }
}

private void addToScene() {
    final JFXPanel menuFxPanel = new JFXPanel();
    add(menuFxPanel);
    Platform.setImplicitExit(false);
    Platform.runLater(() -> {
        Scene scene = new Scene(new VBox(), 400, 20);
        initMenuItem();
        ((VBox) scene.getRoot()).getChildren().addAll(menuBar);
        menuFxPanel.setScene(scene);
    });
}

private void initMenuItem() {
    menuBar = new MenuBar();
    menuItem = new MenuItem("Item 1");
    menuItem.setAccelerator(new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN));
    Menu menu1 = new Menu("Dummy 1");
    menu1.getItems().add(menuItem);
    menuBar.getMenus().add(menu1);
    menuItem.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            System.out.println(".handle()");
        }
    });
}
}

The issue is, The accelerator commands (Ctrl+S) works only when the Menubar has focus.If i click on the JTextField(it gains focus) and accelerator commands doesn't work.

To make it work again i have to click on the MenuBar again to gain focus.

I can relate its because i have added JavaFX items over JmenuBar(DummyMenuBar.java) but not sure of exact root cause.

How can i solve this?


Solution

  • I did a work around using KeyBinding,

    public static void main(String[] args) {
            new JFXPanel();
            final JFrame frame = new JFrame();
            frame.setLayout(new BorderLayout());
            JTextField tf = new JTextField("Hello World");
            frame.getContentPane().add(tf,
                    BorderLayout.CENTER);
            tf.getInputMap((JComponent.WHEN_FOCUSED)).put(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK), "Ctrl+S");
            tf.getActionMap().put("Ctrl+S", new SaveAction());
            frame.setJMenuBar(new DummyMenuBar());
            frame.setSize(300, 300);
            frame.setVisible(true);
        }
            static class SaveAction extends AbstractAction {
    
            @Override
            public void actionPerformed(java.awt.event.ActionEvent e) {
                if((e.getSource() instanceof JTextField)){
                System.out.println(".handle() in Action");
                }
            }
        }
    

    This Made sure , accelerator worked even when JFXPanel is out of focus.