Pergunta

Eu gostaria de criar uma aplicação ampla atalho de teclado para um aplicativo Java Swing. Looping sobre todos os componentes e adicionar o atalho em cada um, tem efeitos colaterais relacionados foco, e parece ser uma solução de força bruta.

Alguém tem uma solução mais limpa?

Foi útil?

Solução

Instale um KeyEventDispatcher personalizado. A classe KeyboardFocusManager também é um bom lugar para essa funcionalidade.

KeyEventDispatcher

Outras dicas

Para cada janela, use JComponent.registerKeyboardAction com uma condição de WHEN_IN_FOCUSED_WINDOW. Alternativamente uso:

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

conforme descrito na docs registerKeyboardAction API .

Para as pessoas querendo saber (como eu) como usar KeyEventDispatcher, aqui está um exemplo que eu juntos. Ele usa um HashMap para armazenar todas as ações globais, porque eu não gosto de grandes construções 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;
    }
  });
}

O uso de SwingUtils.invokeLater () talvez não seja necessário, mas é provavelmente uma boa idéia para não bloquear o ciclo de eventos global.

Quando você tem um menu, você pode adicionar atalhos de teclado globais para itens de menu:

    JMenuItem item = new JMenuItem(action);
    KeyStroke key = KeyStroke.getKeyStroke(
        KeyEvent.VK_R, KeyEvent.CTRL_DOWN_MASK);
    item.setAccelerator(key);
    menu.add(item);

Um exemplo pouco 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;
  }

});

Use o seguinte pedaço 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);

Substitua "D ctrl" com o atalho que deseja.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top