3

Please have a look at the following code

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class MenuActions extends JFrame
{
    private JMenuBar jmb;
    private JMenu file;
    private JMenuItem open;

    public MenuActions()
    {
        jmb = new JMenuBar();
        file = new JMenu("File");
        open = new JMenuItem("Open");
        open.addActionListener(new MenuAction());
        open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,KeyEvent.VK_P,ActionEvent.CTRL_MASK));

        file.add(open);
        jmb.add(file);

        this.setJMenuBar(jmb);

        getContentPane().add(new JPanel());

        this.setSize(200,200);
        this.setVisible(true);
        this.validate();
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

    private class MenuAction implements ActionListener
    {
        public void actionPerformed(ActionEvent ae)
        {
            JOptionPane.showMessageDialog(null,"OK");

        }
    }
    public static void main(String[]args)
    {
        new MenuActions();
    }
}

In here, I need to fire the EventHandler of the JMenuItem when CTRL+O+P is pressed together, so it will display JOptionPane saying "OK". But as you can see, my attempt is giving an error! How can I do this when three of these keys are pressed together? Please help!

PeakGen
  • 21,894
  • 86
  • 261
  • 463

2 Answers2

3

It looks like you are using wrong version of KeyStroke.getKeyStroke() method - can't even find one taking 3 int parameters. Though, if you want you can use CTL + ALT + P instead of CTL + O + P

Try using this version: http://docs.oracle.com/javase/7/docs/api/javax/swing/KeyStroke.html#getKeyStroke(java.lang.String)

like this: KeyStroke.getKeyStroke("control alt P")

Here try this code example :

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class MenuActions extends JFrame
{
    private JMenuBar jmb;
    private JMenu file;
    private JMenuItem open;

    public MenuActions()
    {
        jmb = new JMenuBar();
        file = new JMenu("File");
        open = new JMenuItem("Open");
        open.setAction(new MenuAction("Open", null, "Click to Open an Existing File.", KeyStroke.getKeyStroke("control alt P")));
        open.setAccelerator(KeyStroke.getKeyStroke("control alt P"));

        file.add(open);
        jmb.add(file);

        this.setJMenuBar(jmb);

        getContentPane().add(new JPanel());

        this.setSize(200,200);
        this.setVisible(true);
        this.validate();
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

    private class MenuAction extends AbstractAction
    {
        public MenuAction(String title, ImageIcon image
                                        , String toolTipText
                                        , KeyStroke acceleratorKey)
        {
            super(title, image);
            putValue(SHORT_DESCRIPTION, toolTipText);
            putValue(SHORT_DESCRIPTION, toolTipText);
            putValue(ACCELERATOR_KEY, acceleratorKey);
        }
        public void actionPerformed(ActionEvent ae)
        {
            JOptionPane.showMessageDialog(null,"OK");
        }
    }
    public static void main(String[]args)
    {
        new MenuActions();
    }
}
nIcE cOw
  • 24,468
  • 7
  • 50
  • 143
Yuriy Nakonechnyy
  • 3,742
  • 4
  • 29
  • 41
  • 2
    Have you even tested this patently wrong answer before giving it? – Hovercraft Full Of Eels May 19 '12 at 15:39
  • Yes, you are right - it won't work as it's not correct against the grammar described in that JavaDoc. Please, ignore this answer – Yuriy Nakonechnyy May 19 '12 at 16:11
  • Pardon me, for the edit, I just added a bit of info and corrected previous links with latest version links :-) – nIcE cOw May 19 '12 at 16:19
  • @Nicecow: this doesn't solve the original problem, that of responding to two letter keys + ctrl key at same time. This can be done with key bindings, or several key listeners, but is not good behavior for a program to have. – Hovercraft Full Of Eels May 19 '12 at 16:23
  • @HovercraftFullOfEels : Too true, but going through the OP's comments it appeared, as if he/she had given a functionality to say something by `CTL + A` now something else needs a functionality, but that thing can be referred to by `A` again, so I just gave OP a slight direction, as to how to add one more key and still use the key that can act as a reference to this new thingy. Though my knowledge is short in the topic, but seems to me, one cannot use two letters, though they can use a combination of `Control Delete`, `Control Alt`, `Control Shift` – nIcE cOw May 19 '12 at 16:28
  • @HovercraftFullOfEels: Keybindings won't work with JMenuItems I guess. I started using these accelerators because of that :) – PeakGen May 19 '12 at 17:12
  • @Sepala please can you show us how Keybindings won't work with JMenu / JMenuItems ???, I can't believe .... – mKorbel May 19 '12 at 18:33
  • if I want to catch `Ctrl+P,P`, what do I do? – Incerteza Nov 24 '13 at 08:17
  • 1
    @Alex I suggest you to add handler for `Ctrl+P` combination and in that handler, do the following: 1. add handler for `P` key which does what you need 2. add timer which will run in say `500ms` and remove above mentioned handler for `P` key. Should you need more detailed description, please post it as separate question and post a link to it here and I'll try to help – Yuriy Nakonechnyy Nov 26 '13 at 13:54
3

to @Pete

you can combine any non_chars accelerators but not possible for keys in range [a-z] && [0-9]

for JMenu(Item) accelerator you can use

KeyEvent or Character.valueOf('char') for characters [a-z] && [0-9]

and as second parameter

Event or ActionEvent or InputEvent, notice each of API implemets different keyboards maps

is possible to combine KeyStroke but with bitwise | or & but returns strange KeyStrokes

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.border.BevelBorder;

public class MenuExample extends JPanel {

    private static final long serialVersionUID = 1L;
    private Icon errorIcon = UIManager.getIcon("OptionPane.errorIcon");
    private Icon infoIcon = UIManager.getIcon("OptionPane.informationIcon");
    private Icon warnIcon = UIManager.getIcon("OptionPane.warningIcon");
    private Icon questIcon = UIManager.getIcon("OptionPane.questionIcon");
    private JTextPane pane;
    private JMenuBar menuBar;

    public MenuExample() {
        menuBar = new JMenuBar();
        JMenu formatMenu = new JMenu("Justify");
        formatMenu.setMnemonic('J');
        MenuAction leftJustifyAction = new MenuAction("Left", errorIcon);
        MenuAction rightJustifyAction = new MenuAction("Right", infoIcon);
        MenuAction centerJustifyAction = new MenuAction("Center", warnIcon);
        MenuAction fullJustifyAction = new MenuAction("Full", questIcon);
        JMenuItem item;
        item = formatMenu.add(leftJustifyAction);
        item.setMnemonic('L');
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.ALT_MASK));
        item = formatMenu.add(rightJustifyAction);
        item.setMnemonic('R');
        item.setAccelerator(KeyStroke.getKeyStroke(ActionEvent.CTRL_MASK | KeyEvent.VK_N, ActionEvent.CTRL_MASK & KeyEvent.VK_B));// CTRL +N
        item = formatMenu.add(centerJustifyAction);
        item.setMnemonic('C');
        item.setAccelerator(KeyStroke.getKeyStroke(InputEvent.ALT_MASK | Character.valueOf('p'), InputEvent.ALT_MASK & Character.valueOf('o')));//ALT+F9
        item = formatMenu.add(fullJustifyAction);
        item.setMnemonic('F');
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Event.CTRL_MASK | Event.SHIFT_MASK));
        menuBar.add(formatMenu);
        menuBar.setBorder(new BevelBorder(BevelBorder.RAISED));

    }

    class MenuAction extends AbstractAction {

        public MenuAction(String text, Icon icon) {
            super(text, icon);
        }

        public void actionPerformed(ActionEvent e) {
            try {
                pane.getStyledDocument().insertString(0, "Action [" + e.getActionCommand() + "] performed!\n", null);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    public static void main(String s[]) {
        MenuExample example = new MenuExample();
        example.pane = new JTextPane();
        example.pane.setPreferredSize(new Dimension(250, 250));
        example.pane.setBorder(new BevelBorder(BevelBorder.LOWERED));
        JFrame frame = new JFrame("Menu Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setJMenuBar(example.menuBar);
        frame.getContentPane().add(example.pane, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • @Sepala: Also consider the benefit of `getMenuShortcutKeyMask()`, illustrated [here](http://stackoverflow.com/a/5129757/230513) and [here](http://stackoverflow.com/a/10575771/230513).. – trashgod May 19 '12 at 19:32
  • Concering your "InputEvent.ALT_MASK & Character.valueOf('o'))". I don't think it makes sense to place character codes in the second argument. According to the doc this parameter is: modifiers - a bitwise-ored combination of any modifiers http://docs.oracle.com/javase/7/docs/api/javax/swing/KeyStroke.html . So all that happens is that use a character code as a bit combination, which difficult to decipher what it will do from reading the source code. –  Nov 16 '12 at 14:21
  • if I want to catch `Ctrl+P,P`, what do I do? – Incerteza Nov 24 '13 at 08:17