即使选择了 JTextField,箭头键 KeyBindings 仍然有效
Have arrow key KeyBindings still work even when JTextField is selected
我正在使用 KeyBindings 并使用 WHEN_IN_FOCUSED_WINDOW 条件,因此按键始终有效。但是,如果 JTextField 已被 selected.
,似乎专门的箭头键(左、右、上、下)KeyBindings 停止工作
简而言之,无论 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();
}
}
在上面的代码中,方框随着方向键移动。但是,如果您select左上角的文本框,该框将不再移动。
更新:
我尝试将 KeyBindings 添加到 @camickr 的回答中给出的 JTextFields,但它似乎没有用。也许我做错了什么?
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 个 InputMaps:
- JComponent.WHEN_FOCUSED
- JComponent.WHEN_ANCESTOR_OF_FOCUSED_
- JComponent.WHEN_IN_FOCUSED_WINDOW
WHEN_FOCUSED 有优先权,因此您不能只将键绑定添加到父面板。
所以在你的情况下你可以:
- 也将绑定添加到文本字段或
- 从文本字段中删除绑定。
编辑:
看看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。
我正在使用 KeyBindings 并使用 WHEN_IN_FOCUSED_WINDOW 条件,因此按键始终有效。但是,如果 JTextField 已被 selected.
,似乎专门的箭头键(左、右、上、下)KeyBindings 停止工作简而言之,无论 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();
}
}
在上面的代码中,方框随着方向键移动。但是,如果您select左上角的文本框,该框将不再移动。
更新:
我尝试将 KeyBindings 添加到 @camickr 的回答中给出的 JTextFields,但它似乎没有用。也许我做错了什么?
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 个 InputMaps:
- JComponent.WHEN_FOCUSED
- JComponent.WHEN_ANCESTOR_OF_FOCUSED_
- JComponent.WHEN_IN_FOCUSED_WINDOW
WHEN_FOCUSED 有优先权,因此您不能只将键绑定添加到父面板。
所以在你的情况下你可以:
- 也将绑定添加到文本字段或
- 从文本字段中删除绑定。
编辑:
看看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。