KeyListener
有焦点问题。也就是说,只有在关注焦点和焦点时才会对关键事件做出响应。
简单的解决方案是将KeyListener
注册的组件注册为可聚焦组件,并使用requestFocusInWindow
,但这不会让组件接收到关键板的焦点。
一个更好的解决办法是使用Key Bindings API,它允许您配置要提出的关键事件所需的焦点水平...
一键绑定例如更新/测试
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestKeyBindings {
public static void main(String[] args) {
new TestKeyBindings();
}
public TestKeyBindings() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new KeyPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class KeyPane extends JPanel {
private Triangle up;
private Triangle down;
private Triangle left;
private Triangle right;
private Set<String> activeKeys;
public KeyPane() {
activeKeys = new HashSet<>(4);
up = new Triangle(20);
down = new Triangle(20);
left = new Triangle(20);
right = new Triangle(20);
AffineTransform at = AffineTransform.getRotateInstance(Math.toRadians(-90), 10, 10);
left.transform(at);
at = AffineTransform.getRotateInstance(Math.toRadians(180), 10, 10);
down.transform(at);
at = AffineTransform.getRotateInstance(Math.toRadians(-270), 10, 10);
right.transform(at);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "upPressed");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "downPressed");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "leftPressed");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "rightPressed");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "upReleased");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "downReleased");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "leftReleased");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "rightReleased");
ActionMap am = getActionMap();
am.put("upPressed", new DirectionAction("up", true));
am.put("downPressed", new DirectionAction("down", true));
am.put("leftPressed", new DirectionAction("left", true));
am.put("rightPressed", new DirectionAction("right", true));
am.put("upReleased", new DirectionAction("up", false));
am.put("downReleased", new DirectionAction("down", false));
am.put("leftReleased", new DirectionAction("left", false));
am.put("rightReleased", new DirectionAction("right", false));
}
public void addKey(String name) {
activeKeys.add(name);
repaint();
}
public void removeKey(String name) {
activeKeys.remove(name);
repaint();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - (up.getBounds().width * 3))/2;
int y = (getHeight() - 10)/2;
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
if (activeKeys.contains("left")) {
g2d.fill(left.createTransformedShape(at));
} else {
g2d.draw(left.createTransformedShape(at));
}
at = AffineTransform.getTranslateInstance(x + 40, y);
if (activeKeys.contains("right")) {
g2d.fill(right.createTransformedShape(at));
} else {
g2d.draw(right.createTransformedShape(at));
}
at = AffineTransform.getTranslateInstance(x + 20, y - 20);
if (activeKeys.contains("up")) {
g2d.fill(up.createTransformedShape(at));
} else {
g2d.draw(up.createTransformedShape(at));
}
at = AffineTransform.getTranslateInstance(x + 20, y + 20);
if (activeKeys.contains("down")) {
g2d.fill(down.createTransformedShape(at));
} else {
g2d.draw(down.createTransformedShape(at));
}
g2d.dispose();
}
public class DirectionAction extends AbstractAction {
private String name;
private boolean pressed;
public DirectionAction(String name, boolean pressed) {
this.name = name;
this.pressed = pressed;
}
@Override
public void actionPerformed(ActionEvent e) {
if (pressed) {
addKey(name);
} else {
removeKey(name);
}
}
}
}
public class Triangle extends Path2D.Double {
public Triangle(int size) {
moveTo(size/2, 0);
lineTo(size, size);
lineTo(0, size);
closePath();
}
}
}
其他问题非常重要;即使操作系统经常无法区分笔记本电脑和外接键盘,而Swing应用程序当然不能。首先打印'keyChar'并查看它的价值。 (此外,它可能会更好地使用'之开关,而不是链接的'if's在这里。) – chrylis