我正在使用 KeyBindings 并使用条件 WHEN_IN_FOCUSED_WINDOW,因此按键始终有效。但是,如果选择了 JTextField,则特定的箭头键(左、右、上、下)KeyBindings 似乎会停止工作。
简单地说,我希望 KeyBindings 始终有效,无论 JComponent 具有焦点。
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
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.JTextField;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.WindowConstants;
public class Test extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
private static JTextField field;
private static JFrame frame;
private static boolean up = false, down = false, left = false, right = false;
private static int x = 275, y = 275;
public static void main(String[] args) {
Test t = new Test();
t.setBounds(0, 0, 1200, 600);
t.setVisible(true);
field = new JTextField();
field.setBounds(20, 20, 100, 20);
Timer repaintTimer = new Timer(2, t);
frame = new JFrame();
frame.setSize(600, 600);
setUpKeyActions(t);
frame.add(field);
frame.add(t);
Dimension dim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocation((dim.width - frame.getWidth()) / 2, (dim.height - frame.getHeight()) / 2);
frame.getContentPane().setLayout(null);
frame.setAlwaysOnTop(true);
frame.setResizable(false);
repaintTimer.start();
frame.setVisible(true);
frame.requestFocus();
}
private static void setUpKeyActions(Test t) {
int condition = WHEN_IN_FOCUSED_WINDOW;
new KeyAction(t, condition, KeyEvent.VK_UP, 0, false) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
up = true;
}
};
new KeyAction(t, condition, KeyEvent.VK_UP, 0, true) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
up = false;
}
};
new KeyAction(t, condition, KeyEvent.VK_LEFT, 0, false) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
left = true;
}
};
new KeyAction(t, condition, KeyEvent.VK_LEFT, 0, true) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
left = false;
}
};
new KeyAction(t, condition, KeyEvent.VK_RIGHT, 0, false) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
right = true;
}
};
new KeyAction(t, condition, KeyEvent.VK_RIGHT, 0, true) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
right = false;
}
};
new KeyAction(t, condition, KeyEvent.VK_DOWN, 0, false) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
down = true;
}
};
new KeyAction(t, condition, KeyEvent.VK_DOWN, 0, true) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
down = false;
}
};
}
private static abstract class KeyAction extends AbstractAction {
private static final long serialVersionUID = 1L;
KeyAction(JComponent component, int condition, int keyCode, int modifiers, boolean onKeyRelease) {
InputMap inputMap = component.getInputMap(condition);
ActionMap actionMap = component.getActionMap();
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers, onKeyRelease);
inputMap.put(keyStroke, keyStroke.toString());
actionMap.put(keyStroke.toString(), this);
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(up)
y -= 1;
if(down)
y += 1;
if(right)
x += 1;
if(left)
x -= 1;
if(x < 0)
x = 0;
else if(x > frame.getWidth() - 30)
x = frame.getWidth() - 30;
if(y < 0)
y = 0;
else if(y > frame.getHeight() - 50)
y = frame.getHeight() - 50;
g.drawRect(x, y, 30, 30);
}
@Override
public void actionPerformed(ActionEvent e) {
frame.repaint();
}
}
在上面的代码中,框通过方向键移动。但是,如果选择左上角的文本框,该框将不再移动。
更新:
我尝试将 KeyBindings 添加到 JTextFields,如 @camickr 的答案中给出的,但它似乎不起作用。也许我做错了什么?
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
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.JTextField;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.WindowConstants;
public class Test extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
private static JFrame frame;
private static boolean up = false, down = false, left = false, right = false;
private static int x = 275, y = 275;
public static void main(String[] args) {
Test t = new Test();
t.setBounds(0, 0, 1200, 600);
t.setVisible(true);
JTextField field = new JTextField();
field.setBounds(20, 20, 100, 20);
Timer repaintTimer = new Timer(2, t);
frame = new JFrame();
frame.setSize(600, 600);
setUpKeyActions(t, field);
frame.add(field);
frame.add(t);
Dimension dim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocation((dim.width - frame.getWidth()) / 2, (dim.height - frame.getHeight()) / 2);
frame.getContentPane().setLayout(null);
frame.setAlwaysOnTop(true);
frame.setResizable(false);
repaintTimer.start();
frame.setVisible(true);
frame.requestFocus();
}
private static void setUpKeyActions(Test t, JTextField field) {
int condition = WHEN_IN_FOCUSED_WINDOW;
new KeyAction(condition, KeyEvent.VK_UP, 0, false, t, field) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
up = true;
}
};
new KeyAction(condition, KeyEvent.VK_UP, 0, true, t, field) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
up = false;
}
};
new KeyAction(condition, KeyEvent.VK_LEFT, 0, false, t, field) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
left = true;
}
};
new KeyAction(condition, KeyEvent.VK_LEFT, 0, true, t, field) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
left = false;
}
};
new KeyAction(condition, KeyEvent.VK_RIGHT, 0, false, t, field) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
right = true;
}
};
new KeyAction(condition, KeyEvent.VK_RIGHT, 0, true, t, field) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
right = false;
}
};
new KeyAction(condition, KeyEvent.VK_DOWN, 0, false, t, field) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
down = true;
}
};
new KeyAction(condition, KeyEvent.VK_DOWN, 0, true, t, field) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
down = false;
}
};
}
private static abstract class KeyAction extends AbstractAction {
private static final long serialVersionUID = 1L;
KeyAction(int condition, int keyCode, int modifiers, boolean onKeyRelease, JComponent component, JComponent... components) {
InputMap inputMap = component.getInputMap(condition);
ActionMap actionMap = component.getActionMap();
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers, onKeyRelease);
inputMap.put(keyStroke, keyStroke.toString());
actionMap.put(keyStroke.toString(), this);
for(JComponent jc : components) {
inputMap = jc.getInputMap(condition);
actionMap = jc.getActionMap();
keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers, onKeyRelease);
inputMap.put(keyStroke, keyStroke.toString());
actionMap.put(keyStroke.toString(), this);
}
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(up)
y -= 1;
if(down)
y += 1;
if(right)
x += 1;
if(left)
x -= 1;
if(x < 0)
x = 0;
else if(x > frame.getWidth() - 30)
x = frame.getWidth() - 30;
if(y < 0)
y = 0;
else if(y > frame.getHeight() - 50)
y = frame.getHeight() - 50;
g.drawRect(x, y, 30, 30);
}
@Override
public void actionPerformed(ActionEvent e) {
frame.repaint();
}
}
最佳答案
I am using KeyBindings and am using the condition WHEN_IN_FOCUSED_WINDOW
有3个InputMap:
- JComponent.WHEN_FOCUSED
- JComponent.WHEN_ANCESTOR_OF_FOCUSED_
- JComponent.WHEN_IN_FOCUSED_WINDOW
WHEN_FOCUSED 具有优先权,因此您不能只将按键绑定(bind)添加到父面板。
所以在你的情况下你可以:
- 将绑定(bind)添加到文本字段或
- 从文本字段中删除绑定(bind)。
参见How to Remove Key Bindings .
编辑:
看看 UIManager Defaults 。它将显示每个组件的默认属性,包括组件使用的InputMap。
因此,对于 JTextField,您可以使用以下方法删除所有文本字段的默认绑定(bind):
InputMap im = (InputMap)UIManager.get("TextField.focusInputMap");
KeyStroke keyStroke = KeyStroke.getKeyStroke("RIGHT");
im.put(keyStroke, "none"); //noop
以上将禁用所有文本字段的右箭头键。然后我相信文本字段的父面板的绑定(bind)现在将变为 Activity 状态。
如果没有,您可以尝试更改文本字段的默认操作。看看Key Bindings 。它将显示每个组件的默认绑定(bind)。因此,您只需替换特定绑定(bind)的操作即可。 像这样的东西:
ActionMap am = (ActionMap)UIManager.get("TextField.actionMap");
am.put("caret-forward", yourRightActionHere);
如果您只想更改某些文本字段,那么您需要从每个文本字段组件获取InputMap 或ActionMap。
关于java - 即使选择了 JTextField,箭头键 KeyBindings 仍然有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51682659/