hmw
hmw

Reputation: 81

trouble with Java KeyListeners...and possibly the programs itself

So the objective (well the starting point anyway) of this program is to press the arrow keys and have bullets come from the middle of the screen in the direction of the arrow. I have four images of bullets I created in paint and am using these two classes:

this is the class that creates and organizes the bullets:

public class BulletAnimator extends JPanel implements ActionListener
{
  int startX,startY;
  boolean yAxis = false;
  boolean xAxis = false;
  Timer animator;
  String direction;


  public BulletAnimator(int sX, int sY, String d)
  {
    direction = d;

    startX = sX;
    startY = sY;

    animator = new Timer (10, this);
    animator.start();
  }

  //chooses the right picture for the right direction
  public ImageIcon chooseBulletPicture ()
  {
    String path = "bullet";

    if (direction.equals("left"))
      path += "LEFT";
    else if (direction.equals ("right"))
      path += "RIGHT";
    else if (direction.equals ("up"))
      path += "UP";
    else
      path += "DOWN";

    path += ".png";

    ImageIcon b= new ImageIcon (path);

    return b;
  }

  public void paintComponent (Graphics g)
  {
    super. paintComponent(g);

    if (startX >= 500 || startY >= 500)
      animator.stop();

    if (direction.equals ("up"))
      startY -=2;
    else if (direction.equals ("down"))
      startY +=2;
    else if (direction.equals ("right"))
      startX += 2;
    else
      startX -=2;


    chooseBulletPicture().paintIcon (this, g, startX, startY);
   }

  public void actionPerformed(ActionEvent e)
  {
    repaint ();
  }
}

and this is the class is to add keyListeners and test it:

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

public class Test extends JFrame implements KeyListener
{
  JFrame f;

  public Test ()
  {
    addKeyListener (this);
    setFocusable (true);

    f = new JFrame ();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);
    f.setSize(500, 500);
  }

  public void keyPressed(KeyEvent e) 
  {
    BulletAnimator s = new BulletAnimator (250, 250, "initialized---blank");

    //creates bullet w/ correct direction
    if (e.getKeyCode() == KeyEvent.VK_RIGHT )
    {
      s = new BulletAnimator (250, 250, "right");
    } 
    else if (e.getKeyCode() == KeyEvent.VK_LEFT ) 
    {
       s = new BulletAnimator (250, 250, "left"); 
    } 
    else if (e.getKeyCode() == KeyEvent.VK_UP ) 
    {
       s = new BulletAnimator (250, 250, "up");
    } 
    else if (e.getKeyCode() == KeyEvent.VK_DOWN )
    {
       s = new BulletAnimator (250, 250, "down");
    }

    System.out.println ("keyPressed method read");//checks if keyPressed method was looked at

    f.add (s);
    repaint();
  }

  public void keyReleased (KeyEvent e)
  {}
  public void keyTyped (KeyEvent e)
  {}

  public static void main (String [] args)
  {
    Test t = new Test ();
  }
}

As you can see I tried to put in a test that says "keyPressed method read"... when the program runs it doesn't print. In fact nothing at all happens its just a grey screen... quite frustrating really. Well thank you in advance if you took the time to look at it, I would greatly appreciate any advice!

Upvotes: 0

Views: 959

Answers (2)

anon
anon

Reputation:

You are extending the JFrame class so that new Test() is creating an (extended) instance of a JFrame and then you are adding a KeyListener to this instance. However, the frame you are making visible is the one you created in the Test() constructor through

f = new JFrame ();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
f.setSize(500, 500);

You did not add your KeyListener to this instance of JFrame. So the KeyListener would only respond if the Test instance was visible and in focus.

I would suggest doing this:

public class Test extends JFrame implements KeyListener {
  JFrame f; // Remove this.

  public Test () {
    super();
    addKeyListener (this);
    setFocusable (true);

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true);
    setSize(500, 500);
  }
}

To paint the Icons, you also need to modify BulletAnimator code:

public void actionPerformed( ActionEvent e ) {
  repaint();
  revalidate();  // new line
}

And change f.add(s) to add(s) in keyPressed method to add the icons to the Test frame.

Disclaimer: As others pointed out, there are better solutions to handling key presses. My suggestions above only identified the problems with your original code posted above.

Upvotes: 2

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285460

Again, don't use KeyListeners, use key bindings which will allow you to listen to key strokes application-wide without as much worry about focus and at a much higher level of abstraction (so safer to use too).

For example:

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.*;

public class Test2 extends JPanel {
   private static final int PREF_W = 400;
   private static final int PREF_H = PREF_W;
   private static final int TIMER_DELAY = 50;
   private Timer leftKeyTimer = new Timer(TIMER_DELAY , new TimerListener());


   public Test2() {
      int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
      InputMap inputMap = getInputMap(condition );
      ActionMap actionMap = getActionMap();

      String leftDownKey = "Left Down";
      String leftUpKey = "Left Up";
      KeyStroke leftDown = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT , 0, false);
      KeyStroke leftUp = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT , 0, true);
      inputMap.put(leftDown, leftDownKey);
      inputMap.put(leftUp, leftUpKey);

      actionMap.put(leftDownKey, new LeftKeyAction(false));
      actionMap.put(leftUpKey, new LeftKeyAction(true));
      leftKeyTimer.setActionCommand("Left Key");
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   private class LeftKeyAction extends AbstractAction {
      private boolean onKeyRelease;

      public LeftKeyAction(boolean onKeyRelease) {
         this.onKeyRelease = onKeyRelease;
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         if (onKeyRelease) {
            if (leftKeyTimer != null && leftKeyTimer.isRunning()) {
               leftKeyTimer.stop();
            }
         } else {
            if (leftKeyTimer != null && !leftKeyTimer.isRunning()) {
               leftKeyTimer.start();
            }

         }
      }
   }

   private class TimerListener implements ActionListener {
      public void actionPerformed(ActionEvent actEvt) {
         System.out.println(actEvt.getActionCommand());
      }
   }

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

      JFrame frame = new JFrame("Test2");
      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();
         }
      });
   }
}

Upvotes: 4

Related Questions