如果你在带有掩码的java中添加一个Key Binding - 让我们只用KeyEvent.VK_A来说ActionEvent.ALT_MASK - 然后你执行那个键(ALT + A)但是你释放了alt键 < / em>在'A'键之前,您通常会遇到一个问题,即类(实现ActionListener)中的actionPerformed()将继续被激活。这可能(98%肯定)意味着密钥绑定从未注册密钥已被释放。如果你在alt键之前释放'A'键,你很好,但是 - 就像我说的 - 如果你在另一个键之前释放alt键大约1/10秒,它会不断重复。
注意:这只发生在我的程序(here)
中如果你不相信我,请亲自尝试一下。以下是我的代码片段:
public ConwayPanel() {
super();
setBackground(new Color(245, 255, 245, 255)); // BG slightly green - all ready
paused = true; // nothing to play... in FUTURE put cool organism in
startX = 0; // starting position of the left of the grid
startY = 0; // starting position of the top of the grid
zoom = 15; // the width of each cell (EXCLUDING the lines that make up the boundaries)
cellNum = 1000; // The number of cells
cells = new boolean[cellNum][cellNum]; // populate cells with false/dead
currentX = 0; // current x cursor position
currentY = 0; // current y cursor position
flipBoundaries = new int[4];
hideCurrentPos = false; // don't want to hide cursor position unless explicitly told to do so
defineMaps(); // creates Key enums
setKeyBindings(); // defines Key and KeyNoMask key bindings
Timer timer = new Timer(100, new KeyListener());
timer.start();
setupMouseListeners(); // creates MouseListener, MouseMotionListener and MouseWheelListener
setFocusable(true); // make isFocusable() true
requestFocusInWindow(); // get focus for listeners
}
private void defineMaps() {
for (KeyAltMask key : KeyAltMask.values()) {
keyMap.put(key, false); // value true when key is pressed - all initiated to false
}
for (KeyNoMask key : KeyNoMask.values()) {
keyNoMaskMap.put(key, false); // value true when key is pressed - all initiated to false
}
}
private void setKeyBindings() {
InputMap inMap = getInputMap(JComponent.WHEN_FOCUSED/* or... WHEN_IN_FOCUSED_WINDOW*/);
ActionMap actMap = getActionMap();
for (final KeyAltMask key : KeyAltMask.values()) {
KeyStroke pressed = KeyStroke.getKeyStroke(key.getKeyCode(), ActionEvent.ALT_MASK, false); // just right! (not blocking shortcut key and preventing accidental keyboard mishaps)
KeyStroke released = KeyStroke.getKeyStroke(key.getKeyCode(), ActionEvent.ALT_MASK, true); // just right! (not blocking shortcut key and preventing accidental keyboard mishaps)
inMap.put(pressed, key.toString() + "pressed");
inMap.put(released, key.toString() + "released");
actMap.put(key.toString() + "pressed", new AbstractAction() { // adds each value of Key into a HashMap (when the key is pressed) and puts that HashMap action into ActionMap
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, true);
}
});
actMap.put(key.toString() + "released", new AbstractAction() { // adds each value of Key into a HashMap (when the key is released) and puts that HashMap action into ActionMap
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, false);
}
});
}
for (final KeyNoMask key : KeyNoMask.values()) {
KeyStroke pressed = KeyStroke.getKeyStroke(key.getKeyCode(), 0, false);
KeyStroke released = KeyStroke.getKeyStroke(key.getKeyCode(), 0, true);
inMap.put(pressed, key.toString() + "pressed");
inMap.put(released, key.toString() + "released");
actMap.put(key.toString() + "pressed", new AbstractAction() { // adds each value of KeyNoMask into a HashMap (when the key is pressed) and puts that HashMap action into ActionMap
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyNoMaskMap.put(key, true);
}
});
actMap.put(key.toString() + "released", new AbstractAction() { // adds each value of KeyNoMask into a HashMap (when the key is released) and puts that HashMap action into ActionMap
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyNoMaskMap.put(key, false);
}
});
}
}
private class KeyListener implements ActionListener { // probably not great to have same name, but "real" KeyListener not imported
@Override
public void actionPerformed(ActionEvent e) {
for (KeyAltMask key : KeyAltMask.values()) { // run through the ALL of the keys
if (keyMap.get(key)) { // if key in HashMap is true (i.e. the actionPerformed() above set it true)
switch(key.toString()) {
case "c": // clear all cells and pause if not paused
for (int y = 0; y < cellNum; y++) {
for (int x = 0; x < cellNum; x++) {
cells[x][y] = false;
}
}
if (!paused) {
paused = true;
}
break;
case "f": // fill all cells and pause if not paused
for (int y = 0; y < cellNum; y++) {
for (int x = 0; x < cellNum; x++) {
cells[x][y] = true;
}
if (!paused) {
paused = true;
}
}
break;
case "i": // invert all cells and pause if not paused
for (int y = 0; y < cellNum; y++) {
for (int x = 0; x < cellNum; x++) {
cells[x][y] = !cells[x][y];
}
if (!paused) {
paused = true;
}
}
break;
case "l": // lock all cells that have a live/true cell
for (int y = 0; y < cellNum; y++) {
for (int x = 0; x < cellNum; x++) {
if (cells[x][y]) {
//set Lock
}
}
}
break;
case "p": // pause/play
paused = !paused;
break;
case "s": // step once
step = true;
break;
case "h": // hide current cursor position
hideCurrentPos = !hideCurrentPos;
break;
// default:
}
}
}
for (KeyNoMask key : KeyNoMask.values()) { // run through ALL of the keys (this is the beauty of key bindings - you can move the cursor diagonally). I kinda like a pause after the first key press, though
if (keyNoMaskMap.get(key)) { // if key in HashMap is true (i.e. the actionPerformed() above returned true)
switch(key.toString()) { // move cursor position appropriately and pause if not paused
case "down":
currentY += currentY == cellNum - 1 ? 0 : 1;
if (!paused) {
paused = true;
}
break;
case "up":
currentY -= currentY == 0 ? 0 : 1;
if (!paused) {
paused = true;
}
break;
case "left":
currentX -= currentX == 0 ? 0 : 1;
if (!paused) {
paused = true;
}
break;
case "right":
currentX += currentX == cellNum - 1 ? 0 : 1;
if (!paused) {
paused = true;
}
break;
case "space": // flip pixel at current cursor position
flipCell(currentX, currentY);
if (!paused) {
paused = true;
}
// default:
}
}
}
}
}
这是很多代码,但它至少是KeyBindings的标准。所以,我想知道是否有办法解决这个问题。这是os的错还是Java的错,我该如何修复它。我想避免在else
中使用actionPerformed()
,因为我需要快速。另外,无论如何都要优化actionPerformed()
方法,因为它似乎有点棘手。
我只是将它们放在一起,但是它不会在这里做到这一点!小可执行文件:
package bindingstest;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
/**
*
* @author Dylan AND Hovercraft Full Of Eels
*/
public class BindingsTest {
static Map<Key, Boolean> keyMap = new HashMap<>();
enum Key { // possibly used in conjunction with mask in order to prevent keyboard mishaps - it will probably be ALT in FUTURE
a(KeyEvent.VK_A),
b(KeyEvent.VK_B),
c(KeyEvent.VK_C),
d(KeyEvent.VK_D),
e(KeyEvent.VK_E),
f(KeyEvent.VK_F);
private final int keyCode;
private Key(int keyCode) {
this.keyCode = keyCode; // KeyEvent.VK_...
}
public int getKeyCode() {
return keyCode;
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setBounds(50, 50, 1000, 1000);
JPanel panel = new JPanel();
panel.setFocusable(true);
panel.requestFocusInWindow();
for (Key key : Key.values()) {
keyMap.put(key, false);
}
InputMap inMap = panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actMap = panel.getActionMap();
for (final Key key : Key.values()) {
KeyStroke pressed = KeyStroke.getKeyStroke(key.getKeyCode(), ActionEvent.ALT_MASK, false);
KeyStroke released = KeyStroke.getKeyStroke(key.getKeyCode(), ActionEvent.ALT_MASK, true);
inMap.put(pressed, key.toString() + "pressed");
inMap.put(released, key.toString() + "released");
actMap.put(key.toString() + "pressed", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, true);
}
});
actMap.put(key.toString() + "released", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, false);
}
});
}
for (final Key key : Key.values()) {
KeyStroke pressed = KeyStroke.getKeyStroke(key.getKeyCode(), 0, false);
KeyStroke released = KeyStroke.getKeyStroke(key.getKeyCode(), 0, true);
inMap.put(pressed, key.toString() + "pressed");
inMap.put(released, key.toString() + "released");
actMap.put(key.toString() + "pressed", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, true);
}
});
actMap.put(key.toString() + "released", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, false);
}
});
}
Timer timer = new Timer(100, new KeyListener());
timer.start();
frame.add(panel);
}
private static class KeyListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
for (Key key : Key.values()) { // run through the ALL of the keys
if (keyMap.get(key)) { // if key in HashMap is true (i.e. the actionPerformed() above set it true)
switch(key.toString()) {
case "a":
System.out.println("a");
break;
case "b":
System.out.println("b");
break;
case "c":
System.out.println("c");
break;
case "d":
System.out.println("d");
break;
case "e":
System.out.println("e");
break;
case "f":
System.out.println("f");
}
}
}
}
}
}
答案 0 :(得分:5)
好的,我知道你在说什么,感谢发布可编辑的代码。一种解决方案是使用释放KeyStrokes,一个用于alt键,一个用于普通键。例如,
InputMap inMap = panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actMap = panel.getActionMap();
for (final Key key : Key.values()) {
KeyStroke altPressed = KeyStroke.getKeyStroke(key.getKeyCode(),
InputEvent.ALT_DOWN_MASK, false);
KeyStroke altReleased = KeyStroke.getKeyStroke(key.getKeyCode(),
InputEvent.ALT_DOWN_MASK, true);
KeyStroke released = KeyStroke.getKeyStroke(key.getKeyCode(),
0, true);
inMap.put(altPressed, altPressed.toString());
inMap.put(altReleased, altReleased.toString());
inMap.put(released, released.toString());
actMap.put(altPressed.toString(), new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, true);
}
});
Action releaseAction = new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, false);
}
};
actMap.put(altReleased.toString(), releaseAction);
actMap.put(released.toString(), releaseAction);
另一个解决方案是不执行上述操作,而是在Timer的每次迭代中重新设置Map:
for (Key key : Key.values()) { // run through the ALL of the keys
if (keyMap.get(key)) { // if key in HashMap is true (i.e. the
// actionPerformed() above set it true)
switch (key.toString()) {
case "a":
System.out.println("a");
break;
case "b":
System.out.println("b");
break;
case "c":
System.out.println("c");
break;
case "d":
System.out.println("d");
break;
case "e":
System.out.println("e");
break;
case "f":
System.out.println("f");
}
// ***** add this *****
keyMap.put(key, Boolean.FALSE);
}
}
第二种解决方案会受到操作系统在按下按键时按键提交的延迟的影响。