我创建了自己的 SSCCE,在测试中,似乎无论使用什么技术,小程序仍然必须请求并获得焦点才能使它们工作。我已经使用两个组件中的任何一个成功地在我的 Windows 系统上工作,包括在 xxx ms 之后请求焦点的 javax.swing.Timer,或者paint(...)
在第一次调用绘制时请求焦点的 JApplet 方法的覆盖(和当小程序刚刚被渲染时)。例如,显示两个 kludges(只需要一个)以及键绑定和 SSCCE 的示例:
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.lang.reflect.InvocationTargetException;
import javax.swing.*;
@SuppressWarnings("serial")
public class KeyBindingEg extends JApplet {
protected static final int TIMER_DELAY = 100;
private boolean firstPane = true;
@Override
public void init() {
createAndShowGui();
}
private void createAndShowGui() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
TestClass test = new TestClass();
getContentPane().add(test);
// a kludge to get focus on the GUI some time after it has been created
new Timer(TIMER_DELAY, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
requestFocusInWindow();
((Timer)e.getSource()).stop();
}
}).start();
}
});
} catch (InterruptedException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
// another kludge to get focus on the GUI after it is
// first rendered
if (firstPane) {
requestFocusInWindow();
firstPane = false;
}
}
}
@SuppressWarnings("serial")
class TestClass extends JPanel {
public TestClass() {
setLayout(new BorderLayout());
add(new JLabel("TestClass", SwingUtilities.CENTER));
int condition = WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
for (KeyInfo keyInfo : KeyInfo.values()) {
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyInfo.getKeyCode(), 0);
inputMap.put(keyStroke , keyInfo.toString());
actionMap.put(keyInfo.toString(), new AbstractAction() {
@Override
public void actionPerformed(ActionEvent evt) {
System.out.println("key press: " + evt.getActionCommand());
}
});
}
}
}
enum KeyInfo {
UP(KeyEvent.VK_W), DOWN(KeyEvent.VK_S), LEFT(KeyEvent.VK_A), RIGHT(KeyEvent.VK_D);
private int keyCode;
private KeyInfo(int keyCode) {
this.keyCode = keyCode;
}
public int getKeyCode() {
return keyCode;
}
}
上面的代码使用了 AncestorListener:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.*;
import java.lang.reflect.InvocationTargetException;
import javax.swing.*;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
@SuppressWarnings("serial")
public class KeyBindingEg extends JApplet {
protected static final int TIMER_DELAY = 100;
private boolean firstPane = true;
@Override
public void init() {
createAndShowGui();
}
private void createAndShowGui() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
TestClass test = new TestClass();
JPanel contentPane = (JPanel) getContentPane();
contentPane.add(test);
contentPane.addAncestorListener(new RequestFocusListener());
}
});
} catch (InterruptedException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
class RequestFocusListener implements AncestorListener {
public void ancestorRemoved(AncestorEvent arg0) {}
public void ancestorMoved(AncestorEvent arg0) {}
@Override
public void ancestorAdded(AncestorEvent aEvt) {
Component comp = (Component) aEvt.getSource();
comp.requestFocusInWindow();
}
}
@SuppressWarnings("serial")
class TestClass extends JPanel {
public TestClass() {
setLayout(new BorderLayout());
add(new JLabel("TestClass", SwingUtilities.CENTER));
int condition = WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
for (KeyInfo keyInfo : KeyInfo.values()) {
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyInfo.getKeyCode(), 0);
inputMap.put(keyStroke, keyInfo.toString());
actionMap.put(keyInfo.toString(), new AbstractAction() {
@Override
public void actionPerformed(ActionEvent evt) {
System.out.println("key press: " + evt.getActionCommand());
}
});
}
}
}
enum KeyInfo {
UP(KeyEvent.VK_W), DOWN(KeyEvent.VK_S), LEFT(KeyEvent.VK_A), RIGHT(
KeyEvent.VK_D);
private int keyCode;
private KeyInfo(int keyCode) {
this.keyCode = keyCode;
}
public int getKeyCode() {
return keyCode;
}
}