为啥 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 仅在按下按钮时才会启动,为啥?

InputBindings只在聚焦时才起作用

为啥 UITableViewCell 上的 UIButton 仅在触摸手势持续很短时间时才会变暗

jQuery悬停仅在悬停一定时间时才起作用

Libgdx - 如何仅在按住鼠标按钮时产生粒子?