我使用的是KeyBindings,并且使用的条件为WHEN_IN_FOCUSED_WINDOW,因此这些键始终有效。但是,如果选择了JTextField,则似乎箭头键(左,右,上,下)的键绑定似乎停止工作。
简而言之,无论JComponent专注于什么,我都希望KeyBindings始终可以工作。
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();
}
}
在上面的代码中,该框随箭头键移动。但是,如果选择左上角的文本框,则该框将不再移动。
更新:
我试图按照@camickr的答案在JTextFields中添加KeyBindings,但是它似乎没有用。也许我做错了什么?
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();
}
}
答案 0 :(得分:2)
我正在使用KeyBindings,并且使用的条件为WHEN_IN_FOCUSED_WINDOW
有3个InputMap:
WHEN_FOCUSED具有优先权,因此您不能仅将键绑定添加到父面板。
因此,您可以:
请参见How to Remove Key Bindings。
编辑:
看看UIManager Defaults。它将显示每个组件的默认属性,包括该组件使用哪些InputMap。
因此对于JTextField,您可以使用以下命令删除所有文本字段的默认绑定:
InputMap im = (InputMap)UIManager.get("TextField.focusInputMap");
KeyStroke keyStroke = KeyStroke.getKeyStroke("RIGHT");
im.put(keyStroke, "none"); //noop
以上内容将禁用所有文本字段的向右箭头键。然后,我相信文本字段父面板的绑定现在将变为活动状态。
如果没有,您可以尝试更改文本字段的默认操作。看一下Key Bindings。它将显示每个组件的默认绑定。因此,您只需将Action替换为特定的绑定即可。 像这样:
ActionMap am = (ActionMap)UIManager.get("TextField.actionMap");
am.put("caret-forward", yourRightActionHere);
如果只想更改某些文本字段,则需要从每个文本字段组件中获取InputMap或ActionMap。