Java键盘监听器未被调用。

10

我用Java编写了一段使用KeyListener的示例代码,我创建了一个JPanel,然后将其设置为可聚焦,创建了一个KeyListener,请求了一个焦点,然后将KeyListener添加到我的面板上。但是,keyListener的方法从未被调用。似乎尽管我请求了焦点,但它并没有获得焦点。

有人能帮忙吗?

listener = new KeyLis();
this.setFocusable(true);
this.requestFocus();
this.addKeyListener(listener);

 class KeyLis implements KeyListener{

    @Override
    public void keyPressed(KeyEvent e) {
        currentver += 5;
         switch (e.getKeyCode()) {
            case KeyEvent.VK_LEFT : if(horizontalyInBounds()) currentPos-= 5;  
                 break;
            case KeyEvent.VK_RIGHT: if(horizontalyInBounds()) currentPos+= 5;  
                 break;
        }
        repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void keyTyped(KeyEvent e) {
    }
}

如果需要提供可运行的代码:

  import java.awt.Color;
  import java.awt.Graphics;
  import java.util.Random;

  import javax.swing.JFrame;
  import javax.swing.JLabel;


 public class test extends JFrame {

private AreaOfGame areaOfGame;

public test()
{
    super("");
    setVisible(true);
    this.setBackground(Color.darkGray);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.pack();
    setLayout(null);
    setBounds(200, 10, 400, 700);

    areaOfGame = new AreaOfGame();
    this.add(areaOfGame);

    startGame();
}

public int generateNext()
{
    Random r = new Random();
    int n = r.nextInt(7);
    return n;
}

public void startGame()
{
    while(!areaOfGame.GameOver())
    {
        areaOfGame.startGame(generateNext());
    }
}


public static void main(String[] args) {
    new MainFrame();
}


import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.JPanel;

public class AreaOfGame extends JPanel {


    private static final int rightside = 370;

    private int bottom;
    private int top;

    private int currentPos;
    private int currentver;
    private KeyLis listener;

    public AreaOfGame()
    {
        super();

        bottom = 650;
        top = 50;
        setLayout(null);
        setBounds(20, 50, 350, 600);
        setVisible(true);


        this.setBackground(Color.lightGray);

        listener = new KeyLis();
        this.setFocusable(true);
        if(this.requestFocus(true))
            System.out.println("true");;
        this.addKeyListener(listener);


        currentPos = 150;
        currentver=0;
    }

    public void startGame(int n)
    {
        while(verticallyInBound()){
            System.out.println("anything");

        }


    }

    public boolean verticallyInBound()
    {
        if(currentPos<= bottom -50)
            return true;
        return false;
    }


    public boolean GameOver()
    {
        if(top>= bottom){
            System.out.println("game over");
            return true;
        }

        else return false;
    }


    public boolean horizontalyInBounds()
    {
        if(currentPos<=rightside && currentPos>= 20)
            return true;
        else return false;
    }


class KeyLis implements KeyListener{

        @Override
        public void keyPressed(KeyEvent e) {
            System.out.println("called");
            currentver += 5;
             switch (e.getKeyCode()) {
                case KeyEvent.VK_LEFT : if(horizontalyInBounds()) currentPos-= 5;  break;
                case KeyEvent.VK_RIGHT: if(horizontalyInBounds()) currentPos+= 5;  break;
            }
            repaint();


        }

        @Override
        public void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void keyTyped(KeyEvent e) {
            System.out.println("called 3");
        }
}

}

1
如果您能提供“KeyLis”类,可能会有帮助,也许问题就在那里。 - eboix
谢谢,我已经添加了监听器类。 - BBB
只需将您的代码复制到keyPressed方法中。 - RoflcoptrException
1
@BBB 请尝试在您的监听器的每个方法中添加 System.out.println("something unique")。这将确保它们实际上没有被调用。 - Jon Egeland
1
你的 while (true) 循环正在卡住你的事件线程。 - Hovercraft Full Of Eels
显示剩余7条评论
2个回答

21
我打赌您在JPanel渲染之前(在顶层窗口调用pack()setVisible(true)之前)请求了焦点,如果是这样,那么这种方法不起作用。只有组件被呈现后,才有可能授予焦点请求。您是否检查过您对requestFocus()的调用返回了什么?它必须返回true,否则您的调用就没有任何成功的机会。此外,最好使用requestFocusInWindow()而不是requestFocus()
但更重要的是,您不应该使用KeyListeners,而应该使用键绑定,这是Swing自身用于响应按键的更高级别概念。 编辑
一个SSCCE示例:
import java.awt.Dimension;
import java.awt.event.*;
import javax.swing.*;

public class TestKeyListener extends JPanel {
   private KeyLis listener;

   public TestKeyListener() {
      add(new JButton("Foo")); // something to draw off focus
      listener = new KeyLis();
      this.setFocusable(true);
      this.requestFocus();
      this.addKeyListener(listener);
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(300, 200);
   }

   private class KeyLis extends KeyAdapter {
      @Override
      public void keyPressed(KeyEvent e) {
         switch (e.getKeyCode()) {
         case KeyEvent.VK_LEFT:
            System.out.println("VK_LEFT pressed");
            break;
         case KeyEvent.VK_RIGHT:
            System.out.println("VK_RIGHT pressed");
            break;
         }
      }
   }

   private static void createAndShowGui() {
      TestKeyListener mainPanel = new TestKeyListener();

      JFrame frame = new JFrame("TestKeyListener");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

编辑2
使用键绑定的等效SSCCE:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class TestKeyBindings extends JPanel {

   public TestKeyBindings() {
      add(new JButton("Foo")); // something to draw off focus
      setKeyBindings();
   }

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

      String vkLeft = "VK_LEFT";
      String vkRight = "VK_RIGHT";
      inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), vkLeft);
      inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), vkRight);

      actionMap.put(vkLeft, new KeyAction(vkLeft));
      actionMap.put(vkRight, new KeyAction(vkRight));

   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(300, 200);
   }

   private class KeyAction extends AbstractAction {
      public KeyAction(String actionCommand) {
         putValue(ACTION_COMMAND_KEY, actionCommand);
      }

      @Override
      public void actionPerformed(ActionEvent actionEvt) {
         System.out.println(actionEvt.getActionCommand() + " pressed");
      }
   }

   private static void createAndShowGui() {
      TestKeyBindings mainPanel = new TestKeyBindings();

      JFrame frame = new JFrame("TestKeyListener");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

编辑 3
关于您最近提供的 SSCCE,您的 while (true) 循环会阻塞 Swing 事件线程,可能会妨碍用户交互或绘图发生。最好使用 Swing 定时器而不是 while (true)。例如:

import java.awt.*;
import java.awt.event.*;
import java.util.Random;

import javax.swing.*;

public class BbbTest extends JFrame {

   private AreaOfGame areaOfGame;

   public BbbTest() {
      super("");
//      setVisible(true);
      this.setBackground(Color.darkGray);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      this.pack();
      setLayout(null);
      setBounds(200, 10, 400, 700);

      areaOfGame = new AreaOfGame();
      this.add(areaOfGame);
      setVisible(true);

      startGame();
   }

   public int generateNext() {
      Random r = new Random();
      int n = r.nextInt(7);
      return n;
   }

   public void startGame() {
      // while (!areaOfGame.GameOver()) {
      // areaOfGame.startGame(generateNext());
      // }

      areaOfGame.startGame(generateNext());
   }

   public static void main(String[] args) {
      new BbbTest();
   }

   class AreaOfGame extends JPanel {

      private static final int rightside = 370;

      private int bottom;
      private int top;

      private int currentPos;
      private int currentver;
      private KeyLis listener;

      public AreaOfGame() {
         super();

         bottom = 650;
         top = 50;
         setLayout(null);
         setBounds(20, 50, 350, 600);
         setVisible(true);

         this.setBackground(Color.lightGray);

         listener = new KeyLis();
         this.setFocusable(true);
         if (this.requestFocus(true))
            System.out.println("true");
         ;
         this.addKeyListener(listener);

         currentPos = 150;
         currentver = 0;
      }

      public void startGame(int n) {
         // while (verticallyInBound()) {
         // System.out.println("anything");
         // }

         int timeDelay = 50; // msecs delay
         new Timer(timeDelay , new ActionListener() {

            public void actionPerformed(ActionEvent arg0) {
               System.out.println("anything");
            }
         }).start();

      }

      public boolean verticallyInBound() {
         if (currentPos <= bottom - 50)
            return true;
         return false;
      }

      public boolean GameOver() {
         if (top >= bottom) {
            System.out.println("game over");
            return true;
         }

         else
            return false;
      }

      public boolean horizontalyInBounds() {
         if (currentPos <= rightside && currentPos >= 20)
            return true;
         else
            return false;
      }

      class KeyLis implements KeyListener {

         @Override
         public void keyPressed(KeyEvent e) {
            System.out.println("called");
            currentver += 5;
            switch (e.getKeyCode()) {
            case KeyEvent.VK_LEFT:
               if (horizontalyInBounds())
                  currentPos -= 5;
               break;
            case KeyEvent.VK_RIGHT:
               if (horizontalyInBounds())
                  currentPos += 5;
               break;
            }
            repaint();

         }

         @Override
         public void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub

         }

         @Override
         public void keyTyped(KeyEvent e) {
            System.out.println("called 3");
         }
      }
   }
}

实际上,这些都是在我的框架调用pack()和setVisible(true)之后完成的。如果使用键绑定是唯一的选择,那我会这样做,但我真的很想知道为什么这不起作用,因为似乎之前没有人遇到过这个问题,我检查了空指针,焦点,方法被调用,侦听器已添加,但都没有奏效。 - BBB
@BBB:再次确认一下,你是否检查了requestFocus()方法的返回值?它是返回true还是false? - Hovercraft Full Of Eels
@BBB:现在有一个使用键绑定进行说明的SSCCE。 - Hovercraft Full Of Eels
谢谢!现在它被称为,我刚刚添加了你添加的JButton :D 现在它们被调用了,我不知道为什么这可能会导致监听器被调用,但还是谢谢:D - BBB
非常感谢您的所有帮助,我还添加了计时器,现在它运行得非常好:D 感谢您的时间和帮助。 - BBB
显示剩余3条评论

0

可以使用“TAB”按钮在按钮和键监听器之间切换。 我有一个程序,其中一个按钮按下后,键监听器不起作用。 我意识到,如果按下“TAB”按钮,则程序的“注意力”或“焦点”将返回到键监听器。

也许这会有所帮助:http://docstore.mik.ua/orelly/java-ent/jfc/ch03_08.htm


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接