2008-09-19 31 views
27

Me gustaría crear un atajo de teclado de aplicación para una aplicación Java Swing. Looping sobre todos los componentes y agregando el atajo en cada uno, tiene efectos secundarios relacionados con el enfoque, y parece una solución de fuerza bruta.Atajo de teclado de aplicación completo - Java Swing

¿Alguien tiene una solución más limpia?

Respuesta

20

Instalar un KeyEventDispatcher personalizado. La clase KeyboardFocusManager también es un buen lugar para esta funcionalidad.

KeyEventDispatcher

37

Para cada ventana, utilice JComponent.registerKeyboardAction con una condición de WHEN_IN_FOCUSED_WINDOW. Alternativamente use:

JComponent.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(keyStroke, command); 
JComponent.getActionMap().put(command,action); 

como se describe en el registerKeyboardAction API docs.

+0

+1 Lo mejor, respuesta más fácil que he encontrado. Voy a renunciar a este x1000 –

+3

x1001 sería mejor, de esa manera al menos recibiría un voto favorable. – Epaga

+0

@Epaga O 999 veces –

6

Cuando se tiene un menú, puede añadir 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); 
13

Para las personas preguntándose (como yo) cómo utilizar KeyEventDispatcher, aquí es un ejemplo que puse juntos. Utiliza un HashMap para almacenar todas las acciones globales, porque no me gustan las construcciones grandes if (key == ..) then .. else if (key == ..) then .. else if (key ==..) ...

/** 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() es tal vez no es necesario, pero es probablemente una buena idea de no bloquear el bucle de eventos global.

+0

No es la solución más simple, pero definitivamente la más elegante y confiable. –

-1

Utilice el siguiente fragmento de 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); 

Reemplazar "Ctrl D" con el acceso directo que desee.

+0

no, eso está desactualizado api (reemplazado por actionMap/inputMap desde jdk 1.2 o 1.3 - camino atrás en la edad de piedra) – kleopatra

+0

@kleopatra Hmm. Gracias por el comentario. Quiero saber el motivo. ¡No lo encontré! – user12458

+0

no entiendo del todo, ¿por qué? – kleopatra

1

Un pequeño ejemplo 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; 
    } 

}); 
Cuestiones relacionadas