10

I have written a sample code using KeyListener in Java, I have created a JPanel, then set its focusable to true, I have created a KeyListener, requested a focus and then added the KeyListener to my panel. But the methods for the keyListener are never called. It seems although I have requested focus, it does not focus.

Can anyone help?

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) {
    }
}

If any runnable code should be needed:

  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");
        }
}

}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
BBB
  • 305
  • 1
  • 6
  • 19

2 Answers2

21

I'll bet that you're requesting focus before the JPanel has been rendered (before the top level window has either had pack() or setVisible(true) called), and if so, this won't work. Focus request will only be possibly granted after components have been rendered. Have you checked what your call to requestFocus() has returned? It must return true for your call to have any chance for a success. Also it's better to use requestFocusInWindow() rather than requestFocus().

But more importantly, you shouldn't be using KeyListeners for this but rather key bindings, a higher level concept that Swing itself uses to respond to key presses.

Edit
An example of an 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();
         }
      });
   }
}

Edit 2
And the equivalent SSCCE using Key Bindings:

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();
         }
      });
   }
}

Edit 3
Regarding your recent SSCCE, your while (true) loops are blocking your Swing event thread and may prevent user interaction or painting from happening. Better to use a Swing Timer rather than while (true). For example:

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");
         }
      }
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Actually these are all done after my frame has had pack() and setVisible(true).If using key bindings is the only choice I will do that, but I would really like to know why this does not work, because no body seemed to have this problem before, I checked for null pointers, for focuses, for methods being called, the listener being added, but non worked. – BBB Dec 13 '11 at 01:43
  • @BBB: again, have you checked with your `requestFocus()` method call has returned? Is it returning true or false? – Hovercraft Full Of Eels Dec 13 '11 at 01:45
  • it is returning false all the time – BBB Dec 13 '11 at 01:46
  • this is actually what I have mentioned in my question, although I request, it seems it is not focused , meaning that it returns false and I dont know how to make it return true. – BBB Dec 13 '11 at 01:47
  • @BBB: my point exactly. Then you have no hope for success unless you change something. Better if you could create and post a small compilable and runnable program that we can run and that demonstrates your problem so we can see it for ourselves, an [sscce](http://sscce.org). – Hovercraft Full Of Eels Dec 13 '11 at 01:48
  • @BBB: now an SSCCE that uses key bindings for illustrative purposes. – Hovercraft Full Of Eels Dec 13 '11 at 02:07
  • Thankssss :D it is now called, i just added that JButton you added :D and now they get called, I dont have any idea why this might cause the listener to be called but thanks :D – BBB Dec 13 '11 at 02:33
  • Thank you so much for all the help, I also added the timer, and now it works really fine :D Thanks for the time and help – BBB Dec 13 '11 at 02:43
0

It's possible to use the "TAB" button to switch between the buttons and the key listener. I have a program with one button that after I press it, the key listener does not work. I realized that if you press the "TAB" button, the "Attention" or "focus" of the program returns to the key listener.

maybe this will help: http://docstore.mik.ua/orelly/java-ent/jfc/ch03_08.htm