Atajo de teclado para toda la aplicación - Java Swing
Pregunta
Me gustaría crear un método abreviado de teclado para toda la aplicación para una aplicación Java Swing.Recorrer todos los componentes y agregar el acceso directo a cada uno tiene efectos secundarios relacionados con el enfoque y parece una solución de fuerza bruta.
¿Alguien tiene una solución más limpia?
Solución
Instale un KeyEventDispatcher personalizado.La clase KeyboardFocusManager también es un buen lugar para esta funcionalidad.
Otros consejos
Para cada ventana, utilice JComponent.registerKeyboardAction
con una condición de WHEN_IN_FOCUSED_WINDOW
.Utilice alternativamente:
JComponent.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(keyStroke, command);
JComponent.getActionMap().put(command,action);
como se describe en el registrarseDocumentos de la API de KeyboardAction.
Para las personas que se preguntan (como yo) cómo usar KeyEventDispatcher, aquí hay un ejemplo que preparé.Utiliza un HashMap para almacenar todas las acciones globales, porque no me gustan las grandes if (key == ..) then .. else if (key == ..) then .. else if (key ==..) ..
construcciones.
/** map containing all global actions */
private HashMap<KeyStroke, Action> actionMap = new HashMap<KeyStroke, Action>();
/** call this somewhere in your GUI construction */
private void setup() {
KeyStroke key1 = KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK);
actionMap.put(key1, new AbstractAction("action1") {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Ctrl-A pressed: " + e);
}
});
// add more actions..
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
kfm.addKeyEventDispatcher( new KeyEventDispatcher() {
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);
if ( actionMap.containsKey(keyStroke) ) {
final Action a = actionMap.get(keyStroke);
final ActionEvent ae = new ActionEvent(e.getSource(), e.getID(), null );
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
a.actionPerformed(ae);
}
} );
return true;
}
return false;
}
});
}
El uso de SwingUtils.invokeLater() quizás no sea necesario, pero probablemente sea una buena idea no bloquear el bucle de eventos global.
Cuando tienes un menú, puedes agregar atajos de teclado globales a los elementos del menú:
JMenuItem item = new JMenuItem(action);
KeyStroke key = KeyStroke.getKeyStroke(
KeyEvent.VK_R, KeyEvent.CTRL_DOWN_MASK);
item.setAccelerator(key);
menu.add(item);
Un ejemplo un poco simplificado:
KeyboardFocusManager keyManager;
keyManager=KeyboardFocusManager.getCurrentKeyboardFocusManager();
keyManager.addKeyEventDispatcher(new KeyEventDispatcher() {
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
if(e.getID()==KeyEvent.KEY_PRESSED && e.getKeyCode()==27){
System.out.println("Esc");
return true;
}
return false;
}
});
Utilice el siguiente código
ActionListener a=new ActionListener(){
public void actionPerformed(ActionEvent ae)
{
// your code
}
};
getRootPane().registerKeyboardAction(a,KeyStroke.getKeyStroke("ctrl D"),JComponent.WHEN_IN_FOCUSED_WINDOW);
Reemplace "ctrl D" con el acceso directo que desee.