Reputation: 81
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
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
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