0

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!

hmw
  • 81
  • 1
  • 6
  • 2
    1) Is the `JFrame` focusable? 2) For better help sooner, post an [SSCCE](http://sscce.org/). 3) Note that [Key Bindings](http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html) are generally recommended over `KeyListener`. 4) Both extending `JFrame` and having an instance of one is probably wrong. 5) `f.setSize(500, 500);` If the rendering area should be 500x500, set that as the preferred size of the `BulletAnimator`, and call `pack()` on the frame after it is added. – Andrew Thompson Dec 06 '11 at 02:27
  • 2
    Take a look at this post, should help you : http://stackoverflow.com/questions/286727/java-keylistener-for-jframe-is-being-unresponsive – kz3 Dec 06 '11 at 02:29
  • No, don't add a key listener to every component -- use key bindings as Andrew suggests -- that's what they're for. – Hovercraft Full Of Eels Dec 06 '11 at 02:34
  • 1
    Also, you've got program logic inside of a paintComponent method (where you tell a Timer to stop and increment or decrement variables) -- something you should never do as you do not have full control as to when or even if paintComponent is fired. Instead, these should be in your game loop. – Hovercraft Full Of Eels Dec 06 '11 at 02:39
  • 1
    edit: your game loop here is the animator timer. that logic code in your paintComponent should be in the `actionPerformed` method before `repaint()` – Hovercraft Full Of Eels Dec 06 '11 at 02:48
  • Also, even if you were going to use a KeyListener, you'd need to add the component that is being listened to *first* before anything can be listened to. You've got quite a few things to fix I think. – Hovercraft Full Of Eels Dec 06 '11 at 03:00

2 Answers2

4

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();
         }
      });
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • I moved the logic around in my BulletAnimator class as you suggested, thank you! Also thank you for the example, I'm still pretty shaky on key listeners/key bindings to be honest but it cleared it up a great deal – hmw Dec 06 '11 at 18:51
  • @hmw: I see that you're going with KeyListeners, and I think that you're making a bad mistake. Now what happens if you add a JButton or any other componenet to your GUI? Not to put Kavka down, but I have to ask if he knows enough about this subject and why he also didn't recommend key bindings. – Hovercraft Full Of Eels Dec 06 '11 at 19:19
  • @Hovercraft... alright, I don't have much to do this afternoon so learn key bindings it is! Thank you again – hmw Dec 06 '11 at 19:53
  • @Hovercraft Full Of Eels, I am definitely not an expert on key bindings and have no problem with your strong suggestion to the OP. My answer is only addressing the "bug" on OP's original code: the fact that there were two frames involved and that the OP installed the KeyListener on the wrong one. – Kavka Dec 06 '11 at 21:06
2

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.

Kavka
  • 4,191
  • 16
  • 33
  • @Andrew Thompson. Thanks for the correction. I removed the reference to `getContentPane().add()` in my answer. – Kavka Dec 06 '11 at 15:01
  • Kavka, thank you! now my key listener is being read at least, however my bullet animator is not being added to the screen. But when I take the picture used in each bullet animator (a bullet facing in different direction) it adds and changes with the arrows as expected...whenever you get the chance I would greatly appreciate any ideas. – hmw Dec 06 '11 at 19:02
  • @hmw. See additional suggestions in my answer to address painting issues. – Kavka Dec 06 '11 at 22:02