6

I use the following code to create hot keys for the java form using swing. If I press ALT+N,ALT+R,ALT+1,ALT+2 the cursor moves to correct text fields and I enter the value in corresponding Text Fields. It works properly. My problem is, I have Save and exit JButtons in this form if. I press CTRL+S means the Save button will be selected at the same time If i press CTRL+X means the exit button will be selected. How to create mnemonics for JButton? How to do CTRL+S,CTRL+X this using the following code?

Thanks in advance.

package hotkeys;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
public class hotkey extends JFrame {
    public static void main(String arg[]) {
        JLabel Name = new JLabel("Name");
        JTextField tf1 = new JTextField(20);
        Name.setLabelFor(tf1);
        Name.setDisplayedMnemonic('N');


        JLabel Regno = new JLabel("RegNO");
        JTextField tf2 = new JTextField(20);
        Regno.setLabelFor(tf2);
        Regno.setDisplayedMnemonic('R');

        JLabel Mark1 = new JLabel("Mark1");
        JTextField tf3 = new JTextField(20);
        Mark1.setLabelFor(tf3);
        Mark1.setDisplayedMnemonic('1');

        JLabel Mark2 = new JLabel("Mark2");
        JTextField tf4 = new JTextField(20);
        Mark2.setLabelFor(tf4);
        Mark2.setDisplayedMnemonic('2');


        JButton b1 = new JButton("Save");
        JButton b2 = new JButton("eXit");


        JFrame f = new JFrame();
        JPanel p = new JPanel();

        p.add(Name);
        p.add(tf1);
        p.add(Regno);
        p.add(tf2);
        p.add(Mark1);
        p.add(tf3);
        p.add(Mark2);
        p.add(tf4);
        p.add(b1);
        p.add(b2);

        f.add(p);
        f.setVisible(true);
        f.pack();
    }
}
Nayan
  • 1,521
  • 2
  • 13
  • 27
java872
  • 89
  • 1
  • 3
  • 5
  • 2
    please what do you needed else, without any progress??? http://stackoverflow.com/questions/8586353/create-hot-keys-in-java-using-swing, http://stackoverflow.com/questions/8585544/enter-key-using-in-jtextfield-java, http://stackoverflow.com/questions/8584998/hotkeys-creation-for-java-swing-form, – mKorbel Dec 21 '11 at 10:15

4 Answers4

21

You need to register a keyBinding in the button's component inputmap. In code (repeating a subtle variant of what you have been told to do in your previous questions :-)

// create an Action doing what you want
Action action = new AbstractAction("doSomething") {

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("triggered the action");
    }

};
// configure the Action with the accelerator (aka: short cut)
action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control S"));

// create a button, configured with the Action
JButton toolBarButton = new JButton(action);
// manually register the accelerator in the button's component input map
toolBarButton.getActionMap().put("myAction", action);
toolBarButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
        (KeyStroke) action.getValue(Action.ACCELERATOR_KEY), "myAction");
kleopatra
  • 51,061
  • 28
  • 99
  • 211
10

Sun has a really good Description of the whole Key Binding issue. You can find it here:

JavaSE Tutorial on Keybinding

//EDIT

Edited my example code so you can just copy + paste it and it will work. Included the points that were missing, thanks for the feedback.

KeyStroke keySave = KeyStroke.getKeyStroke(KeyEvent.VK_S, Event.CTRL_MASK); 
Action performSave = new AbstractAction("Save") {  
    public void actionPerformed(ActionEvent e) {     
         //do your save
         System.out.println("save");
    }
}; 
JButton b1 = new JButton(performSave); 
b1.getActionMap().put("performSave", performSave);
b1.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keySave, "performSave"); 

KeyStroke keyExit = KeyStroke.getKeyStroke(KeyEvent.VK_Y, Event.CTRL_MASK); 
Action performExit = new AbstractAction("Exit") {  
    public void actionPerformed(ActionEvent e) {     
        //exit
        System.out.println("exit");
    }
}; 
JButton b2 = new JButton(performExit); 
b2.getActionMap().put("performExit", performExit);
b2.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyExit, "performExit"); 
Matschie
  • 1,561
  • 1
  • 11
  • 9
  • good direction - just a bit incomplete: additionally you need to a) register the actions in the button's actionMap b) if you want a window-scope short-cut, register the keyStroke in the "component inputMap", that is the one of type JComponent.WHEN_IN_FOCUSED_WINDOW, instead of the default (which is WHEN_FOCUSED) – kleopatra Dec 21 '11 at 10:33
  • just noticed c) the Action should have its name property set (instead of instantiating the button with a text) - so downvoted for now, will revert once you correct the little issues :-) – kleopatra Dec 21 '11 at 10:46
  • Thanks for your feedback kleopatra. :) I now edited the code samples so it will work after copy + pasting. Have a good day. – Matschie Dec 21 '11 at 13:44
  • Ok right. Is c) correct aswell now? Because I never worked with those names before. Wow learned something new, sweet :) – Matschie Dec 21 '11 at 13:56
  • perfect :-) as very last bit of sugar glazing, you might consider to use the getStroke(String) method which is the recommended way of grabbing one - though a matter of taste at the end of a day – kleopatra Dec 21 '11 at 14:04
1

I provide this as much for me as a learning experience as for anyone else. I've always had difficulty applying code snippets for key binding that I've found in the past and I hope my explanation and code will be clear. Thanks to @kleopatra for her code snippet, on which I base my code below.

(I'm using CAPITAL LETTERS where I should NOT in order to more clearly show what MUST MATCH.)

The code links the Ctrl-Shift-U keystroke to the code in actionPerformed for MYACTION via the matching strings in getInputMap and getActionMap.

The three instances of MYACTION below must match, as must the four instances of MYACTIONBUTTON, as must the two instances of the string MAKE_THESE_MATCH. Call them what you will; just make them match.

The button MYACTIONBUTTON must have MYACTION as the argument to the JButton defining it AND must have getInputMap and getActionMap applied to it.

private static JButton MYACTIONBUTTON;
private static JFrame frame;
private static JPanel panel;

...

Action MYACTION = new AbstractAction()
{

  @Override
  public void actionPerformed(ActionEvent e)
  {
      // put action code here
  }
};

MYACTIONBUTTON = new JButton(MYACTION);

MYACTIONBUTTON.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)

                           .put(getKeyStroke(VK_U, CTRL_DOWN_MASK | SHIFT_DOWN_MASK),

                                  "MAKE_THESE_MATCH"); 

MYACTIONBUTTON.getActionMap().put("MAKE_THESE_MATCH",        MYACTION);

panel.add(MYACTIONBUTTON);

frame.add(panel);
DSlomer64
  • 4,234
  • 4
  • 53
  • 88
1

Just modified your code. (inserted code in //**)
Just 1 comment... Ctrl-X is shortcut for edit command "Cut" (along with Ctrl-C & Ctrl-V). You have editable fields in frame. I used Ctrl-Q (quit) instead.

import java.awt.event.*;
import java.beans.PropertyChangeListener;

import javax.swing.*;
import javax.swing.plaf.ActionMapUIResource;

import java.net.*;

public class HotKeys extends JFrame {
public static void main(String arg[]) {
    JLabel Name = new JLabel("Name");
    JTextField tf1 = new JTextField(20);
    Name.setLabelFor(tf1);
    Name.setDisplayedMnemonic('N');

    JLabel Regno = new JLabel("RegNO");
    JTextField tf2 = new JTextField(20);
    Regno.setLabelFor(tf2);
    Regno.setDisplayedMnemonic('R');

    JLabel Mark1 = new JLabel("Mark1");
    JTextField tf3 = new JTextField(20);
    Mark1.setLabelFor(tf3);
    Mark1.setDisplayedMnemonic('1');

    JLabel Mark2 = new JLabel("Mark2");
    JTextField tf4 = new JTextField(20);
    Mark2.setLabelFor(tf4);
    Mark2.setDisplayedMnemonic('2');

    JButton b1 = new JButton("Save");
    JButton b2 = new JButton("eXit");

    JFrame f = new JFrame();
    JPanel p = new JPanel();

    p.add(Name);
    p.add(tf1);
    p.add(Regno);
    p.add(tf2);
    p.add(Mark1);
    p.add(tf3);
    p.add(Mark2);
    p.add(tf4);
    p.add(b1);
    p.add(b2);

    // *****************************************************
    ActionMap actionMap = new ActionMapUIResource();
    actionMap.put("action_save", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Save action performed.");
        }
    });
    actionMap.put("action_exit", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Exit action performed.");
        }
    });

    InputMap keyMap = new ComponentInputMap(p);
    keyMap.put(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S,
            java.awt.Event.CTRL_MASK), "action_save");
    keyMap.put(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Q,
            java.awt.Event.CTRL_MASK), "action_exit");
    SwingUtilities.replaceUIActionMap(p, actionMap);
    SwingUtilities.replaceUIInputMap(p, JComponent.WHEN_IN_FOCUSED_WINDOW,
            keyMap);
    // *****************************************************

    f.add(p);
    f.setVisible(true);
    f.pack();
}
}
andrey
  • 842
  • 4
  • 6
  • no - you _never_ (read: except when you really intent to :-) want to use those replaceXX methods. a) you install those new maps - at least the ActionMap - for _all_ instances of JPanel b) doesn't survive a switch of LAF – kleopatra Dec 21 '11 at 12:01
  • slight correction to my last comment: b) is incorrect because XXPanelUI doesn't install any maps at all – kleopatra Dec 21 '11 at 12:27
  • I've tried Ctrl-X (java.awt.event.KeyEvent.VK_X) - it was ignored by GUI. After this i changed to java.awt.event.KeyEvent.VK_Q. Perhaps I was wrong in attempt to descibe why, but fact is that java.awt.event.KeyEvent.VK_X didn't work. – andrey Dec 21 '11 at 12:54