我在JFrame
的根窗格中注册了一个事件,该事件在按下空格键时会做出反应(打开另一个窗口)。我在JFrame中也有一个JTextField
。当用户处于我的文本字段的编辑模式并点击空格键时,空间事件应该仅由文本字段使用,而不是转发到JFrame
的动作图。
我该怎么做?
以下是该问题的可运行演示:
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
public class TestDialog {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "spaceAction");
frame.getRootPane().getActionMap().put("spaceAction", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("spaceAction");
}
});
JTextField tf = new JTextField("textfield");
JLabel label = new JLabel("otherComponent");
label.setFocusable(true);
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(tf);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
}
答案 0 :(得分:1)
将空格键用作全局触发器并不是一个好主意。但如果你真的需要它,那么就是这样:
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.text.JTextComponent;
public class DialogTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "spaceAction");
frame.getRootPane().getActionMap().put("spaceAction", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
if (EventQueue.getCurrentEvent() instanceof KeyEvent) {
KeyEvent ke = (KeyEvent) EventQueue.getCurrentEvent();
if (!(ke.getComponent() instanceof JTextComponent)) {
System.out.println("spaceAction");
} else {
System.out.println("Ignore event in text component");
}
} else {
System.out.println("spaceAction");
}
}
});
JTextField tf = new JTextField("textfield");
JLabel label = new JLabel("otherComponent");
label.setFocusable(true);
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(tf);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
}
更好的方法是从根窗格开始遍历组件树,并仅为您需要的组件添加键绑定(例如所有标签)。这是我的遍历方法
/**
* Searches for all children of the given component which are instances of the given class.
*
* @param aRoot start object for search.
* @param aClass class to search.
* @param <E> class of component.
* @return list of all children of the given component which are instances of the given class. Never null.
*/
public static <E> List<E> getAllChildrenOfClass(Container aRoot, Class<E> aClass) {
final List<E> result = new ArrayList<E>();
final Component[] children = aRoot.getComponents();
for (final Component c : children) {
if (aClass.isInstance(c)) {
result.add(aClass.cast(c));
}
if (c instanceof Container) {
result.addAll(getAllChildrenOfClass((Container) c, aClass));
}
}
return result;
}
答案 1 :(得分:0)
我通过创建一个简单的JTextField子类来解决此问题,该子类消耗了用户按下的所有可打印字符。这样,您无需修改封闭组件。
public class JTextFieldNoKeyBinding extends JTextField
{
public JTextFieldNoKeyBinding()
{
// Key presses are processed by JTextField but NOT consumed,
// so they end up being also processed by the key binding framework.
// The only way to block them is to capture all the printable keys: see
// https://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html
for (char c = 32; c <= 126; c++)
{
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(c, 0), "doNothing");
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(c, InputEvent.SHIFT_DOWN_MASK), "doNothing");
}
getActionMap().put("doNothing", new NoAction());
}
private class NoAction extends AbstractAction
{
@Override
public void actionPerformed(ActionEvent e)
{
//do nothing
}
}
}