【问题标题】: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) {
    }

} 

【问题讨论】:

    标签: java swing awt jbutton keylistener


    【解决方案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。键绑定提供了指定将在什么条件下调用它的方法,其中一些不需要组件具有焦点。

      【讨论】:

        猜你喜欢
        • 2011-12-30
        • 2014-02-16
        • 1970-01-01
        • 2021-03-16
        • 1970-01-01
        • 2017-12-27
        • 2013-05-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多