Search code examples
javaswingkeylistenerjmenubar

Adding a keylistener to a JMenuBar


I have the following code for a JMenuBar. How would I add my key listener CustomKeyListener to the entire JMenuBar?

package UI;

import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.*;
import java.awt.Point;
import java.awt.font.*;
import UI.*;

public class GuiDMenuBar extends JMenuBar
{
    JMenu m_file,m_code;
    JMenuItem mi_f_new,mi_f_open;

    public GuiDMenuBar()
    {
        setBorderPainted(true);
        makeFileMenu();
        makeCodeButton();

    }

    void makeFileMenu()
    {
        m_file = new JMenu("File");
        m_file.setMnemonic('F');

        mi_f_new = new JMenuItem("New");
        mi_f_new.setMnemonic('N');
        mi_f_open = new JMenuItem("Open");
        mi_f_open.setMnemonic('O');

        mi_f_new.setAccelerator(KeyStroke.getKeyStroke("control N"));
        mi_f_open.setAccelerator(KeyStroke.getKeyStroke("control O"));

        m_file.add(mi_f_new);
        m_file.add(mi_f_open);

        add(m_file);
    }

    void makeCodeButton()
    {
        m_code = new JMenu("Code");
        m_code.setMnemonic('C');

        add(m_code);
    }

    public void addListeners(ActionListener al)
    {
        mi_f_new.addActionListener(al);
        mi_f_open.addActionListener(al);
    }

    class CustomKeyListener implements KeyListener
    {
        @Override
        public void keyTyped(KeyEvent e)
        {
            System.out.println("Type");
        }

        @Override
        public void keyPressed(KeyEvent e)
        {
            System.out.println("Press");
        }

        @Override
        public void keyReleased(KeyEvent e)
        {
            System.out.println("Release");
        }
    }
}

I have tried adding

    m_code.setFocusable(true);
    m_code.addKeyListener(new CustomKeyListener());

to the void makeCodeButton however that did not pick up when anything was typed for that one JMenu. This is why I want it added to the whole JMenuBar instead.

Edit to show full CustomKeyListener

class CustomKeyListener implements KeyListener
{
    Robot Roby = null;

    @Override
    public void keyTyped(KeyEvent e)
    {
        char c = e.getKeyChar();
        if(c==KeyEvent.VK_ENTER)
        {
            if(m_code.isSelected())
            {
                try
                {
                    Roby = new Robot();
                }

                catch(AWTException awte)
                {
                    awte.printStackTrace();
                }

                clcikComponent(m_file);
            }
        }

        System.out.println("Type");
    }

    @Override
    public void keyPressed(KeyEvent e)
    {
        System.out.println("Press");
    }

    @Override
    public void keyReleased(KeyEvent e)
    {
        System.out.println("Release");
    }

    public void clcikComponent(Component comp)
    {
        Point p = comp.getLocationOnScreen();
        System.out.println(p);

        Roby.mouseMove(p.x,p.y);
        Roby.mousePress(MouseEvent.BUTTON1_MASK);
        Roby.mouseRelease(MouseEvent.BUTTON1_MASK);
    }
}

Solution

  • I still think this is a bad idea. As a user I would find it very confusing to find out that using the Enter key on one menu invokes an Action, while it doesn't do anything on other menus. The suggestion I gave in my comment is a far better solution.

    However, I was curious why it didn't work and I found out that focus is actually on the JRootPane when the menu is displayed (and events are only dispatched to the component with focus). So you could add the KeyListener to the root pane.

    However, there is an easier approach. You can use the JMenu.addMenuKeyListener(...) method. The interface is the same as a KeyListener except all methods include "menu" in the name.