Java KeyListener未检测到键盘输入 [英] Java KeyListener isn't detecting keyboard input

查看:131
本文介绍了Java KeyListener未检测到键盘输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试修改此程序,以便绘制城堡的图像,并且我可以使用向上和向下箭头键缩放此图像。我无法让keylistener工作,程序运行但它没有响应按键。感谢任何帮助。

I'm trying to modify this program so that it draws an image of a castle and I am able to scale this image using the up and down arrow keys. I can't manage to get the keylistener to work, the program runs but it isn't responding to key presses. Any help will be appreciated, thanks.

import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
import java.net.*;
import java.awt.event.*;

public class DrawImage extends JFrame implements KeyListener {
int scale = 1;
    private Image image;
    enter code here
    public static void main(String[] args) {
        new DrawImage();
    }

    public DrawImage() {
        super("DrawImage");
        setSize(600,600);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Toolkit tk = Toolkit.getDefaultToolkit();
        image = tk.getImage(getURL("castle.png"));
        addKeyListener(this);
    }

    private URL getURL(String filename) {
        URL url = null;
        try {
            url = this.getClass().getResource(filename);
        }
        catch (Exception e) { }
        return url;
    }

    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        AffineTransform trans = new AffineTransform();
        trans.scale(scale, scale);
        System.out.println("scale: " + scale);
        g2d.setColor(Color.BLACK);
        g2d.fillRect(0, 0, getSize().width, getSize().height);
        g2d.setTransform(trans);
        g2d.drawImage(image, 0, 40, this);
        addKeyListener(this);
    }

    public void keyReleased(KeyEvent e) { }
    public void keyTyped(KeyEvent e) { }
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_UP) {
            scale++;
        }
        if (key == KeyEvent.VK_DOWN) {
            scale--;
        }
    }
}


推荐答案


我无法让keylistener工作,程序运行但它没有响应按键。

I can't manage to get the keylistener to work, the program runs but it isn't responding to key presses.

这是一个非常常见的问题,在这里经常被问到,几乎总是问题是由于缺乏焦点 - 被收听的组件没有当前的焦点,焦点是KeyListener工作的必要条件。

Yours is a very common problem that is asked here frequently, and almost always the problem is due to lack of focus -- that the component being listened to does not have the current focus, and focus is essential for a KeyListener to work.

简短的回答是给正在听取焦点的组件。

The short answer is to give the component that is being listened to the focus.

答案越长越好是不使用KeyListeners,而是使用Key Bindings来实现这样的项目。

The longer better answer is to not use KeyListeners and instead to use Key Bindings for such a project.

编辑

其他问题:

Edit
Other problems:


  • 在上面的代码中,您将KeyListener添加到JFrame中,这不应该即使你有充分的理由使用KeyListeners也不会这样做。

  • 你也直接在JFrame中绘图,在我看来这是一个更大的问题,因为你冒了不必要的风险效果。

  • 您在paint方法中添加了一个侦听器,这是一个更大的问题。不应该覆盖paint方法(通常),如果你必须覆盖它,则永远不应该用于程序逻辑,添加或删除侦听器,或进行任何非绘制活动。它应该只用于绘画和绘画。

  • 相反,你应该直接在JPanel或JComponent中绘制。

  • 相反,你应该在绘图中 paintComponent(Graphics g)覆盖你的绘画JPanel或JComponent。

  • 如上所述,这个方法应该用于绘画和绘画只有而且应该尽可能快。

  • 你应该在<$ c $里面调用 super.paintComponent(g) c> paintComponent(Graphics g)覆盖。

  • 绘图组件应该再次使用Key Bindings监听击键(教程这里)。本教程将解释为什么这种区别(KeyListener与Key Bindings)很重要。


  • In your code above, you're adding the KeyListener to a JFrame, and this shouldn't be done, even if you had good reason to use KeyListeners.
  • You're also drawing directly in the JFrame which in my opinion is an even bigger problem, since you risk unwanted side effects.
  • You're adding a listener inside of the paint method, an even bigger problem. The paint method should not be overridden (in general), and if you did have to override it, should never be used for program logic, for adding or removing listeners, or for doing any non-painting activities. It should be for painting and painting only.
  • Instead you should draw directly in a JPanel or JComponent.
  • Instead you should do the drawing in a paintComponent(Graphics g) override in your painting JPanel or JComponent.
  • Just as described above, this method should be for painting and painting only and should be as fast as possible.
  • You should call the super.paintComponent(g) inside of your paintComponent(Graphics g) override.
  • Again the drawing component should listen for key strokes using Key Bindings (tutorial here). The tutorial will explain why this distinction (KeyListener vs. Key Bindings) is important.

编辑2

你永远不想忽略异常,因为你的代码在这里显示,因为这是相当于驾驶盲人的编程:

Edit 2
You never want to ignore exceptions as your code shows here since this is the programming equivalent of driving blind:

  try {
     url = this.getClass().getResource(filename);
  } catch (Exception e) {
  }

希望这不是怎么回事你的生产代码看起来很简单,你只是为了简洁而忽略了你发布的代码中的异常,但我们很多人都明白这就像在粉笔板上听到指甲一样。

Hopefully this is not how your production code looks, that you only ignored the exceptions in your posted code for the sake of brevity, but understand for many of us seeing this is like hearing nails on a chalk-board.

编辑3

关于KeyListeners与Key Bindings的更多信息:假设您的代码与KeyListener一起使用,然后假设您向GUI添加了任何其他可聚焦组件,并且他们通过用户交互以某种方式获得了焦点,那么您的KeyBindings将不再起作用。如果您使用键绑定正确完成了此操作,则不会出现问题。

Edit 3
More on KeyListeners vs. Key Bindings: Assuming that you got your code to work with a KeyListener, then assume that you added any other focusable components to your GUI and they somehow got the focus via user interaction, then your KeyBindings will no longer work. If you had done this correctly with Key Bindings, this would not be an issue.

编辑4

你真的希望你的scale字段是double,而不是int。并且你真的不想增加和减少它,而是你想要乘以它并将它除以一些乘数常数,比如1.2作为例子。每当你改变你的比例时,你也会想要调用 repaint()

编辑5


请查看两个示例程序,第一个名为DrawImagePanelKeyListener.java,使用KeyListener,而第二个名为DrawImagePanelKeyBindings,使用键绑定。它们都应按预期编译,运行和运行:当您按向上或向下箭头键时,显示的图像会缩小并增大。当按下JButton时,可以看到它们的行为差异。按下按钮,查看您的密钥响应会发生什么。当具有KeyListener的组件失去焦点时,其KeyListener将停止工作,但对于使用键绑定的组件则不同。

Edit 5
Please check out two sample programs, the first, called DrawImagePanelKeyListener.java, uses a KeyListener, while the second, called DrawImagePanelKeyBindings, uses Key Bindings. They both should compile, run, and function as expected: when you press the up or down arrow keys, the displayed image shrinks and grows. The difference in their behavior though can be seen when the JButton both have is pressed. Press the button and see what happens to your key response. When the component that has a KeyListener loses focus, its KeyListener will stop working, but the same is not true for the component that uses Key Bindings.

可能获得的kludge围绕这个问题可能是为了防止所有其他组件获得焦点,但对于大多数GUI来说这是不实际或不可取的。

A kludge that could get around this problem could be to prevent all other components from getting the focus, but that is not practical or desired with most GUI's.

import java.awt.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.io.IOException;
import java.net.*;
import java.awt.event.*;

@SuppressWarnings("serial")
public class DrawImagePanelKeyListener extends JPanel implements KeyListener {
   public static final String IMAGE_PATH = "https://duke.kenai.com/"
         + "nyanya/.Midsize/NyaNya.jpg.png";
   private static final double MULTIPLIER = 1.2;
   double scale = 1.0;
   private Image image;
   private Dimension initialSize = new Dimension(0, 0);

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            DrawImagePanelKeyListener drawImage = new DrawImagePanelKeyListener();
            drawImage.add(new JButton("Foo"));
            JFrame frame = new JFrame("Draw Image");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(drawImage);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
         }
      });
   }

   public DrawImagePanelKeyListener() {
      setFocusable(true);
      requestFocusInWindow();
      URL imgURL;
      try {
         imgURL = new URL(IMAGE_PATH);
         image = ImageIO.read(imgURL);
         initialSize = new Dimension(image.getWidth(this),
               image.getHeight(this));
         addKeyListener(this);
         setVisible(true);
      } catch (MalformedURLException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }

   @Override
   public Dimension getPreferredSize() {
      return initialSize;
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.setColor(Color.BLACK);
      g.fillRect(0, 0, getSize().width, getSize().height);
      Graphics2D g2d = (Graphics2D) g.create();
      g2d.scale(scale, scale);
      g2d.drawImage(image, 0, 0, this);
   }

   public void keyReleased(KeyEvent e) {
   }

   public void keyTyped(KeyEvent e) {
   }

   public void keyPressed(KeyEvent e) {
      int key = e.getKeyCode();
      if (key == KeyEvent.VK_UP) {
         scale *= MULTIPLIER;
      }
      if (key == KeyEvent.VK_DOWN) {
         scale /= MULTIPLIER;
      }
      repaint();
   }
}



DrawImagePanelKeyBindings.java



DrawImagePanelKeyBindings.java

import java.awt.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.io.IOException;
import java.net.*;
import java.awt.event.*;

@SuppressWarnings("serial")
public class DrawImagePanelKeyBindings extends JPanel {
   public static final String IMAGE_PATH = "https://duke.kenai.com/"
         + "nyanya/.Midsize/NyaNya.jpg.png";
   private static final double MULTIPLIER = 1.2;
   double scale = 1.0;
   private Image image;
   private Dimension initialSize = new Dimension(0, 0);

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            DrawImagePanelKeyBindings drawImage = new DrawImagePanelKeyBindings();
            drawImage.add(new JButton("Foo"));
            JFrame frame = new JFrame("Draw Image");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(drawImage);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
         }
      });
   }

   public DrawImagePanelKeyBindings() {
      setBindings();
      URL imgURL;
      try {
         imgURL = new URL(IMAGE_PATH);
         image = ImageIO.read(imgURL);
         initialSize = new Dimension(image.getWidth(this),
               image.getHeight(this));
         setVisible(true);
      } catch (MalformedURLException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }

   private void setBindings() {
      int condition = WHEN_IN_FOCUSED_WINDOW;
      InputMap inputMap = getInputMap(condition);
      ActionMap actionMap = getActionMap();

      final KeyStroke[] keyStrokes = {
            KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
            KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)
      };
      for (final KeyStroke keyStroke : keyStrokes) {
         inputMap.put(keyStroke, keyStroke.toString());
         actionMap.put(keyStroke.toString(), new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent evt) {
               myKeyPressed(keyStroke.getKeyCode());
            }
         });
      }
   }

   @Override
   public Dimension getPreferredSize() {
      return initialSize;
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.setColor(Color.BLACK);
      g.fillRect(0, 0, getSize().width, getSize().height);
      Graphics2D g2d = (Graphics2D) g.create();
      g2d.scale(scale, scale);
      g2d.drawImage(image, 0, 0, this);
   }

   public void myKeyPressed(int key) {
      if (key == KeyEvent.VK_UP) {
         scale *= MULTIPLIER;
      }
      if (key == KeyEvent.VK_DOWN) {
         scale /= MULTIPLIER;
      }
      repaint();
   }
}

这篇关于Java KeyListener未检测到键盘输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆