在网上这方面的例子没找到好用的, 写了个, 以后就可以很方便的注册应用程序级的快捷键了.
注册方式
ShortcutManager.getInstance().addShortcutListener(new ShortcutManager.ShortcutListener() {
public void handle() {
System.out.println("Ctrl + Meta + M");
}
}, KeyEvent.VK_CONTROL, KeyEvent.VK_META, KeyEvent.VK_M);源码:
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;public class ShortcutManager implements AWTEventListener {
// 使用单态模式
private static ShortcutManager instance = new ShortcutManager(); // 快捷键与事件处理对象键值对
private Map<String, ShortcutListener> listeners; // 某组件上发生了快捷键列表中的快捷键事件, 如果他的父组件在被忽略组件列表中, 则放弃这个事件.
private Set<Component> ignoredComponents; // 保存键盘上键与它的ascii码对应
// 如果以某键的ascii码为下标, 数组中此下标的值为true, 说明此键被按下了.
// 当此键被释放开后, 数组中对应的值修改为false
private boolean[] keys; private ShortcutManager() {
keys = new boolean[256];
ignoredComponents = new HashSet<Component>();
listeners = new HashMap<String, ShortcutListener>(); // 只关心键盘事件
Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
} /**
 * 有键盘事件发生
 */
public void eventDispatched(AWTEvent event) {
if (event.getClass() == KeyEvent.class) {
KeyEvent ke = (KeyEvent) event; if (ke.getID() == KeyEvent.KEY_PRESSED) {
keys[ke.getKeyCode()] = true; // 查找快捷键对应的处理对象, 然后调用事件处理函数
String shortcut = searchShortcut();
ShortcutListener l = listeners.get(shortcut);
if (l != null && !isIgnored(event)) {
l.handle();
}
} else if (ke.getID() == KeyEvent.KEY_RELEASED) {
keys[ke.getKeyCode()] = false;
}
}
} protected String searchShortcut() {
// 每个键之间用一个"."来隔开.
// 例如ctr + x的对应值为"17.88."
StringBuilder shortcut = new StringBuilder();
for (int i = 0; i < keys.length; ++i) {
if (keys[i]) {
shortcut.append(i).append(".");
}
}
// System.out.println(shortcut.toString());
return shortcut.toString();
} /**
 * 查找此快捷键事件是否要被抛弃
 * 
 * @param event
 * @return
 */
protected boolean isIgnored(AWTEvent event) {
if (!(event.getSource() instanceof Component)) {
return false;
} boolean ignored = false;
for (Component com = (Component) event.getSource(); com != null; com = com.getParent()) {
if (ignoredComponents.contains(com)) {
ignored = true;
break;
}
} return ignored;
} public static ShortcutManager getInstance() {
return instance;
} public void removeShortcutListener(ShortcutListener l) {
String tempKey = null;
for (Map.Entry<String, ShortcutListener> e : listeners.entrySet()) {
if (e.getValue().equals(l)) {
tempKey = e.getKey();
}
} listeners.remove(tempKey);
} public void addShortcutListener(ShortcutListener l, int... keys) {
// 快捷键的对应值按它们的键顺序大小来进行创建
StringBuilder sb = new StringBuilder();
Arrays.sort(keys);
for (int i = 0; i < keys.length; ++i) {
sb.append(keys[i]).append(".");
} String shortcut = sb.toString(); // 如果还不存在, 则加入
if (listeners.containsKey(shortcut)) {
System.out.println("The shourt cut is already used.");
} else {
listeners.put(shortcut, l);
}
} public void addIgnoredComponent(Component com) {
ignoredComponents.add(com);
} public void removeDiscardComponent(Component com) {
ignoredComponents.remove(com);
} public static interface ShortcutListener {
void handle();
}
}
测试:
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;public class ShortcutTest {
/**
 * 测试使用
 * 
 * @param args
 */
public static void main(String[] args) {
JFrame frame = new JFrame(); JButton button = new JButton("Button");
JTextArea textArea = new JTextArea();
JScrollPane scroller = new JScrollPane(textArea);
frame.getContentPane().add(button, BorderLayout.NORTH);
frame.getContentPane().add(scroller, BorderLayout.CENTER); // ////////////////////////////////////////////////////////////////////////////////////
// 注册快捷键方法
ShortcutManager.getInstance().addShortcutListener(new ShortcutManager.ShortcutListener() {
public void handle() {
System.out.println("Meta + I");
}
}, KeyEvent.VK_META, KeyEvent.VK_I); ShortcutManager.getInstance().addShortcutListener(new ShortcutManager.ShortcutListener() {
public void handle() {
System.out.println("Ctrl + Meta + M");
}
}, KeyEvent.VK_CONTROL, KeyEvent.VK_META, KeyEvent.VK_M); // 测试忽略文本输入里面的快捷键事件, 当按钮得到焦点时, 快捷键事件能正常发生
ShortcutManager.getInstance().addIgnoredComponent(textArea);
// ///////////////////////////////////////////////////////////////////////////////////// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setVisible(true);
}
}

解决方案 »

  1.   

    更新注册的快捷键合法性的判断:
    public void addShortcutListener(ShortcutListener l, int... keys) {
    // 快捷键的对应值按它们的键顺序大小来进行创建
    StringBuilder sb = new StringBuilder();
    Arrays.sort(keys);

    for (int i = 0; i < keys.length; ++i) {
    if (0 < keys[i] && keys[i] < keys.length) {
    sb.append(keys[i]).append(".");
    } else {
    System.out.println("Key is not valid");
    return;
    }
    } String shortcut = sb.toString(); // 如果还不存在, 则加入
    if (listeners.containsKey(shortcut)) {
    System.out.println("The shourt cut is already used.");
    } else {
    listeners.put(shortcut, l);
    }
    }
      

  2.   

    晕, 少写了个this就发上来了:
    if (0 < keys[i] && keys[i] < this.keys.length) {