2008-09-19 12 views
27

Ich möchte eine anwendungsweite Tastenkombination für eine Java Swing-Anwendung erstellen. Schleifen über alle Komponenten und Hinzufügen der Verknüpfung auf jedem, hat Fokus bezogene Nebenwirkungen und scheint wie eine Brute-Force-Lösung.Anwendungsbreite Tastaturkürzel - Java Swing

Jeder hat eine sauberere Lösung?

Antwort

20

Installieren Sie einen benutzerdefinierten KeyEventDispatcher. Die KeyboardFocusManager-Klasse ist auch ein guter Platz für diese Funktionalität.

KeyEventDispatcher

37

Für jedes Fenster, benutzen Sie JComponent.registerKeyboardAction mit einer Bedingung von WHEN_IN_FOCUSED_WINDOW. Alternativ verwenden Sie:

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

wie in der registerKeyboardAction API docs beschrieben.

+0

+1 Die beste und einfachste Antwort, die ich gefunden habe. Ich werde diese x1000 –

+3

x1001 upvote wäre besser, auf diese Weise würde er zumindest eine Aufwertung bekommen. – Epaga

+0

@Epaga Oder 999 mal –

6

Wenn Sie ein Menü haben, können Sie globale Tastaturkürzel Menüpunkte hinzufügen:

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

Für Leute (wie mich) fragen, wie KeyEventDispatcher zu verwenden, hier ist ein Beispiel, das ich zusammen. Es verwendet eine HashMap zum Speichern aller globalen Aktionen, weil ich große if (key == ..) then .. else if (key == ..) then .. else if (key ==..) .. Konstrukte nicht mag.

/** 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; 
    } 
    }); 
} 

Die Verwendung von SwingUtils.invokeLater() ist vielleicht nicht notwendig, aber es ist wahrscheinlich eine gute Idee, nicht die globale Ereignisschleife zu sperren.

+0

Nicht die einfachste Lösung, aber definitiv die eleganteste und zuverlässigste. –

-1

Verwenden Sie das folgende Stück Code

ActionListener a=new ActionListener(){ 
    public void actionPerformed(ActionEvent ae) 
    { 
    // your code 
    } 
}; 
getRootPane().registerKeyboardAction(a,KeyStroke.getKeyStroke("ctrl D"),JComponent.WHEN_IN_FOCUSED_WINDOW); 

Ersetzen Sie "ctrl D" mit der Verknüpfung, die Sie wollen.

+0

nein, das ist veraltet api (ersetzt durch actionMap/inputMap seit jdk 1.2 oder 1.3 - zurück in der Steinzeit) – kleopatra

+0

@kleopatra Hmm. Danke für den Kommentar. Ich möchte den Grund wissen. Ich habe es nicht gefunden! – user12458

+0

nicht ganz verstehen - Grund für was? – kleopatra

1

Ein wenig vereinfachtes Beispiel:

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; 
    } 

});