为啥 KeyListener 仅在未按下按钮时才起作用?
Posted
技术标签:
【中文标题】为啥 KeyListener 仅在未按下按钮时才起作用?【英文标题】:Why does the KeyListener only work when did`t pressed the button?为什么 KeyListener 仅在未按下按钮时才起作用? 【发布时间】:2018-11-12 05:08:08 【问题描述】:当我按下 ESC 键时,我想制作一个 KeyListener 来停止程序。但它只有在我什么都不做(按下按钮)时才有效。如果这是非常明显的事情,我很抱歉,但我找不到错误。
package basics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Graphic extends JFrame implements ActionListener, KeyListener
private JButton button;
public Graphic()
button = new JButton();
button.addActionListener(this);
button.setIcon(new ImageIcon("Image.jpg"));
this.getContentPane().add(button);
public void actionPerformed(ActionEvent e)
if(e.getSource() == button)
//some code
public static void main(String[] args)
JFrame bec = new Graphic();
bec.setDefaultCloseOperation(Graphic.EXIT_ON_CLOSE);
bec.setSize(1731, 563);
bec.setVisible(true);
bec.setTitle("title");
bec.requestFocus();
bec.addKeyListener(new Graphic());
@Override
public void keyPressed(KeyEvent e)
if(e.getKeyCode() == KeyEvent.VK_ESCAPE)
System.exit(0);
@Override
public void keyReleased(KeyEvent e)
@Override
public void keyTyped(KeyEvent e)
【问题讨论】:
【参考方案1】:KeyListener
存在与可聚焦性和 GUI 中其他控件相关的问题。一个简单的解决方案是使用Actions API。在这种方法下,对于给定的组件,程序只需指定任何感兴趣的键与按下(或释放)该键时要调用的 Action(命令)对象之间的“绑定”或“映射”。键绑定与特定的 GUI 组件相关联。
在这种情况下,适当的解决方案可能是:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
public class Graphic extends JFrame implements ActionListener
private JButton button;
public Graphic()
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "Cancel"); //$NON-NLS-1$
getRootPane().getActionMap().put("Cancel", new AbstractAction() //$NON-NLS-1$
public void actionPerformed(ActionEvent e)
dispose();
);
button = new JButton();
button.addActionListener(this);
button.setIcon(new ImageIcon("Image.jpg"));
this.getContentPane().add(button);
public void actionPerformed(ActionEvent e)
if(e.getSource() == button)
//some code
public static void main(String[] args)
JFrame bec = new Graphic();
bec.setDefaultCloseOperation(Graphic.EXIT_ON_CLOSE);
bec.setSize(1731, 563);
bec.setVisible(true);
bec.setTitle("title");
bec.requestFocus();
【讨论】:
我投了赞成票,但如果您提到KeyListener
和键绑定(使其工作)之间的区别,这将是一个更好的答案。
@AndrewThompson 感谢您的建议。我添加了进一步的解释
很好..等等..什么?谁对这个答案投了反对票?不管是谁做的,愿意分享你的推理吗?我很困惑。【参考方案2】:
您确定没有 TextArea 或其他可聚焦的东西吗?他们可以获得焦点,关键事件将传递给他们而不是监听器。
UPD:抱歉,没看到你那里只有按钮。
【讨论】:
【参考方案3】:您的问题是在所有组件中捕获KeyListener
。你可以这样做:
public Graphic()
// ...
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(e ->
if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
dispose();
return true;
return false;
);
添加后,您的应用程序将在您按下ESC
按钮后关闭。如果你想阻止它,例如如果你们中的一些组件有焦点(例如 JTextField
并且您想要执行特定操作),那么您必须在此侦听器中关注组件并避免调用 dispose()
。
【讨论】:
@Rcordoval 是的,它仅在Frame
有焦点时才有效。我已经修改了示例来修复它。【参考方案4】:
但它只有在我什么都不做(按下按钮)时才有效。
不,它不起作用(根本)。看看这段代码:
public static void main(String[] args)
JFrame bec = new Graphic();
// ..
bec.addKeyListener(new Graphic());
键侦听器被添加到从未显示的Graphic
的第二个实例中。
它不起作用的另一个原因:因为KeyListener
(即使添加到正确的实例)要求它添加到的组件都是可聚焦的(JFrame
默认情况下不是)并且具有输入焦点(这个框架永远不会有,因为它是不可聚焦的)。
解决方案:对于 Swing,我们通常使用 key bindings 而不是较低级别的 KeyListener
。键绑定提供了指定将在什么条件下调用它的方法,其中一些不需要组件具有焦点。
【讨论】:
以上是关于为啥 KeyListener 仅在未按下按钮时才起作用?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 xmlHttpRequest.Open 仅在我输入字符串时才起作用?
WPF Focused Visual State 仅在按下按钮时才会启动,为啥?