views:

74

answers:

3

So I've been working on a simple program while learning Java that brings up a small rectangular screen that has a circle moving around on it. The background and circle also change colors and speeds.

Now I'm trying to add KeyEvents, such that when the user types a character, the circle will change directions. I've been trying to get a handle on the KeyEvent feature for a few hours now, and I'm stuck.

How would you change the following code so that the program responds to the keyboard input:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.JFrame;

public class MovingCircle3 extends JFrame implements ActionListener {

    Ellipse2D.Double myEllipse;
    Rectangle2D.Double backgroundRectangle;
    private int paintTally = 0;     // Counts # of repaints.
    private int timerSpeed = 500;   // Holds speed of timer. Initially: 500ms.
    private Timer timerOjbect;
    private char shapeMoveInput = 'd';

    public MovingCircle3() {
        myEllipse = new Ellipse2D.Double(30, 30, 20, 20); // Ellipse starting point
        backgroundRectangle = new Rectangle2D.Double(0, 0, 400, 300); // Background.
        this.timerOjbect = new Timer(500, this);
        timerOjbect.start();                 //Creates and starts timer.
    }

    public static void main(String[] args) {
        System.out.print("Game Controls: \n  l = Move left. \n  r = Move right. \n  u = Move up. \n  d = Move down. \n    ENTER COMMAND: ");    // Game controls.

        MovingCircle3 b = new MovingCircle3();

        b.setVisible(true);
        b.setSize(400, 300);
        b.setVisible(true);
        b.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public void keyPressed(KeyEvent e) {
        try {
            shapeMoveInput = e.getKeyChar();
        } catch (Exception ex) {
            shapeMoveInput = 'd';
        }
    }

    public void actionPerformed(ActionEvent ae) {
        //This will be called by the Timer
        if (shapeMoveInput == 'l') {
            myEllipse.setFrame(myEllipse.getX() - 1, myEllipse.getY(), myEllipse.getWidth(), myEllipse.getHeight());   //Move 1 x-pixel left 
        } else if (shapeMoveInput == 'r') {
            myEllipse.setFrame(myEllipse.getX() + 1, myEllipse.getY(), myEllipse.getWidth(), myEllipse.getHeight());   //Move 1 x-pixel right
        } else if (shapeMoveInput == 'u') {
            myEllipse.setFrame(myEllipse.getX(), myEllipse.getY() - 1, myEllipse.getWidth(), myEllipse.getHeight());   //Move 1 y-pixel up
        } else if (shapeMoveInput == 'd') {
            myEllipse.setFrame(myEllipse.getX(), myEllipse.getY() + 1, myEllipse.getWidth(), myEllipse.getHeight());   //Move 1 y-pixel
        }
        repaint();
    }

    public void paint(Graphics g) {
        paintTally++; // Increments by one for every repaint().
        if (paintTally % 25 == 0) { // Take modulus 25 of paintTally to execute every 25 paints.
            timerSpeed = (int) (timerSpeed / 2);
            timerOjbect.setDelay(timerSpeed); // Divide speed by 2 and see to timer length.  
        }
        int isPaintTen = (int) (paintTally / 10);  // Divide current count by 10.
        Graphics2D g2 = (Graphics2D) g;
        if ((isPaintTen % 2) == 0) { // Take modulus to set if #/10 is odd or even.
            g2.setColor(Color.YELLOW);
            g2.fill(backgroundRectangle);
            g2.setColor(Color.RED);
            g2.draw(myEllipse);

        } else if ((isPaintTen % 2) == 1) {
            g2.setColor(Color.RED);
            g2.fill(backgroundRectangle);
            g2.setColor(Color.YELLOW);
            g2.draw(myEllipse);
        }
    }
}
+1  A: 

Hey there it would seem you are in need of a KeyListener but ActionListener will work on your JFrame. It looks like you are implementing the ActionListener which is a superclass of the key listener. You are implementing it correctly but after that you need to register a new listener, this causes the Event thread in Swing to send events to this listener. The Event thread is a system managed thread. You can read up on this Event Thread at oracles/Suns website. Also just a side note it uses the Observer Pattern if you are interested.

All you need to do is in initialization MovingCircle3() do the following

this.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                movingcircle3_Function(e);
            }
        });  

or you could try the following but i am unsure if it would work properly

this.addActionListener(this);

kohlerfc
+1  A: 

Read up on InputMap and ActionMap. (tutorial here) It's a two-step process of mapping keyboard strokes to an ID and then IDs to calling a method.

Jason S
+1  A: 

1) You should NEVER (unless you really know what you are doing) override the paint method of a JFrame. Custom painting is done by overriding the paintComponent(...) method of a JPanel. Then you add the custom panel to the JFrame. You where given a link to the Swing tutorial in the comments of your original posting. Read the section on Custom Painting for more information and working examples.

2) You would then need to add the KeyListener to the panel. However, KeyEvents are only passed to the component with focus so you need to make the panel focusable by using the setFocusable(...) method on the panel.

However, a KeyListener is not the proper way to solve this problem. You should be using Key Bindings which are far more flexible than using KeyListeners. Again there is a section in the Swing tutorial on "How to Use Key Bindings".

camickr