Java - KeyListener Events not firing - java

I have begun to write a simple platform game in java. As a test, I wrote this simple
program that moves a rectangle around the applet when you press the arrow keys. The key events have not been firing at all. Here's the code:
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class Game extends Applet implements Runnable, KeyListener
{
//setup data
Thread t;
Image buffimg;
Graphics draw;
Dimension dim;
//game variables
int charx = 400;//rectangles X and Y positions
int chary = 50;
boolean leftArrow = false;
public void init()
{
setSize(800, 500);
t = new Thread(this);
t.start();
addKeyListener( this );
}
public void run()
{
while(true)
{
repaint();
moveChar();//move the rectangle
try {
t.sleep(1000/30);
} catch (InterruptedException e) { ; }
}
}
public void keyPressed( KeyEvent e )
{
int k = e.getKeyCode();
if(k == 37)
{
leftArrow = true;
charx--;
}
}
public void keyReleased( KeyEvent e )
{
if(e.getKeyCode() == 37)
{
leftArrow = false;
}
}
public void keyTyped( KeyEvent e )
{
}
public void moveChar()
{
//move rectangle on left arrow key press
if(leftArrow == true)
{
charx--;
}
}
public void paint(Graphics g)
{
g.drawRect(charx, chary, 100, 100);
}
public void update (Graphics g)
{
//double buffering
// initialize buffer
if (buffimg == null)
{
buffimg = createImage (this.getSize().width, this.getSize().height);
draw = buffimg.getGraphics ();
}
// clear screen in background
draw.setColor (getBackground ());
draw.fillRect (0, 0, this.getSize().width, this.getSize().height);
// draw elements in background
draw.setColor (getForeground());
paint (draw);
// draw image on the screen
g.drawImage (buffimg, 0, 0, this);
}
}
Why aren't they firing and how should I fix this?

this.requestFocusInWindow(); // end of init(), or better, in start()

I tried your code. It works as it should.
The problem is you need to press the mouse on the drawing area to focus it first before it can receive events.
To do it automatically, use this command: requestFocusInWindow()

Related

Make graphics move on key events

I'm trying to make a circle capable of moving when the keys "i, j, k, l" are pressed (as arrow keys) and stop when released. Tried creating a Timer in order to wait a second before moving again so the animation is appreciable, but since I created the 'while(!quit)' loop, no graphics move or show. Could you please indicate my errors please?
Code:
import java.awt.*;
import java.awt.Color.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.Timer;
import java.util.TimerTask;
public class Event_test{
public static void main(String args[])
{
boolean quit = false;
JFrame Window = new JFrame("Event_test");
MyCanvas WCanvas = new MyCanvas();
KeyCatcher k = new KeyCatcher();
WCanvas.addKeyListener(k);
Window.getContentPane().add(WCanvas);
Window.setSize(640, 360);
Window.setVisible(true);
Window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
new Notification(1);
while(!quit)
{
WCanvas.update(WCanvas.getGraphics());
if(!Notification.flag)
{
continue;
}
else
{
Notification.flag = false;
System.out.println("tic");
/*
CONTROLS:
*/
if(KeyCatcher.KEYS[0])
{
MyCanvas.x--;
}
if(KeyCatcher.KEYS[1])
{
MyCanvas.y++;
}
if(KeyCatcher.KEYS[2])
{
MyCanvas.x++;
}
if(KeyCatcher.KEYS[3])
{
MyCanvas.y--;
}
if(KeyCatcher.KEYS[4])
{
quit = true;
}
new Notification(1);
}
}
}
}
class MyCanvas extends Canvas
{
static int x, y;
public void paint(Graphics g)
{
g = this.getGraphics();
MyClass.drawSomething(g, x, y);
}
}
class MyClass
{
public static void drawSomething(Graphics g, int x, int y)
{
g.setColor(Color.RED);
g.drawOval(x, y, 10, 10);
}
}
class KeyCatcher implements KeyListener
{
static boolean KEYS[] = new boolean[5];
public void keyPressed(KeyEvent e)
{
if(e.getKeyChar() == 'j'/*IZQ*/)
{
KEYS[0] = true;
}
if(e.getKeyChar() == 'i'/*ARR*/)
{
KEYS[1] = true;
}
if(e.getKeyChar() == 'l'/*DER*/)
{
KEYS[2] = true;
}
if(e.getKeyChar() == 'k'/*ABA*/)
{
KEYS[3] = true;
}
if(e.getKeyChar() == 'q'/*QUIT*/)
{
KEYS[4] = true;
}
}
public void keyReleased(KeyEvent e)
{
if(e.getKeyChar() == 'j'/*IZQ*/)
{
KEYS[0] = false;
}
if(e.getKeyChar() == 'i'/*ARR*/)
{
KEYS[1] = false;
}
if(e.getKeyChar() == 'l'/*DER*/)
{
KEYS[2] = false;
}
if(e.getKeyChar() == 'k'/*ABA*/)
{
KEYS[3] = false;
}
if(e.getKeyChar() == 'q'/*QUIT*/)
{
KEYS[4] = false;
}
}
public void keyTyped(KeyEvent e){
}
}
class Notification{
static boolean flag = false;
Timer timer;
Notification(int seconds)
{
timer = new Timer();
timer.schedule(new Task(), seconds*1000);
}
class Task extends TimerTask
{
public void run()
{
//What task does:
flag = true;
timer.cancel();
}
}
}
Your question is about Swing (not AWT) so:
Don't extend Canvas. Instead custom painting is done by extending a JPanel
Don't override paint(...). Custom painting is done by overrding paintComponent(...)
Don't use a TimerTask. Instead use a Swing Timer.
Don't use the getGraphics() method. See point 2.
Don't invoke update(...). You just invoke repaint() on the component and it will paint iself.
Don't use a while loop. That is the reason for using the Swing Timer.
Don't start variable names with an upper case character. Follow Java naming conventions.
Don't use a KeyListener. Swing was designed to be used with Key Bindings.
Check out the Swing tutorial on Custom Painting for basic painting examples to get you started.
Check out Motion Using the Keyboard. The Keyboard Animation example addresses many of these issues.

Difference between implementing JFrame and JPanel

I was trying to understand the difference between JFrame and JPanel. I tend to use subclasses of JFrame instead of JPanel, but people always tell me that it's better to use a subclass of JPanel instead. Here is an example of me using JFrame:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
public class Game extends JFrame implements Runnable {
int x, y, xCoord, yCoord;
private Image dbImage;
private Graphics dbg;
public void move() {
x += xCoord;
y += yCoord;
if (x <= 20) {
x = 20;
}
if (x >= 480) {
x = 480;
}
if (y <= 40) {
y = 40;
}
if (y >= 480) {
y = 480;
}
}
public void setXCoord(int xcoord) {
xCoord = xcoord;
}
public void setYCoord(int ycoord) {
yCoord = ycoord;
}
public class AL extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
setXCoord(-1);
}
if (keyCode == e.VK_RIGHT) {
setXCoord(+1);
}
if (keyCode == e.VK_UP) {
setYCoord(-1);
}
if (keyCode == e.VK_DOWN) {
setYCoord(+1);
}
Game.this.repaint();
}
#Override
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
setXCoord(0);
}
if (keyCode == e.VK_RIGHT) {
setXCoord(0);
}
if (keyCode == e.VK_UP) {
setYCoord(0);
}
if (keyCode == e.VK_DOWN) {
setYCoord(0);
}
Game.this.repaint();
}
}
public static void main(String[] args) {
Game game = new Game();
Thread t = new Thread(game);
t.start();
}
public Game() {
addKeyListener(new AL());
setTitle("Game");
setSize(500, 500);
setResizable(true);
setVisible(true);
setBackground(Color.BLACK);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x = 250;
y = 250;
}
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
#Override
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
#Override
public void run() {
try {
while (true) {
move();
Thread.sleep(30);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
This works fine (except for there being a small delay when I hold down one of the buttons), but when I try to change my code by implementing JPanel instead of JFrame, nothing shows up... Here's the code for the JPanel subclass:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JPanel implements Runnable {
int x, y, xCoord, yCoord;
private Image dbImage;
private Graphics dbg;
JFrame frame;
public void move() {
x += xCoord;
y += yCoord;
if (x <= 20) {
x = 20;
}
if (x >= 480) {
x = 480;
}
if (y <= 40) {
y = 40;
}
if (y >= 480) {
y = 480;
}
}
public void setXCoord(int xcoord) {
xCoord = xcoord;
}
public void setYCoord(int ycoord) {
yCoord = ycoord;
}
public class AL extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
setXCoord(-1);
}
if (keyCode == e.VK_RIGHT) {
setXCoord(+1);
}
if (keyCode == e.VK_UP) {
setYCoord(-1);
}
if (keyCode == e.VK_DOWN) {
setYCoord(+1);
}
Game.this.repaint();
}
#Override
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
setXCoord(0);
}
if (keyCode == e.VK_RIGHT) {
setXCoord(0);
}
if (keyCode == e.VK_UP) {
setYCoord(0);
}
if (keyCode == e.VK_DOWN) {
setYCoord(0);
}
Game.this.repaint();
}
}
public static void main(String[] args) {
Game game = new Game();
Thread t = new Thread(game);
t.start();
}
public Game() {
frame = new JFrame();
frame.addKeyListener(new AL());
frame.setTitle("Game");
frame.setSize(500, 500);
frame.setResizable(true);
frame.setVisible(true);
frame.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x = 250;
y = 250;
}
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
#Override
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
#Override
public void run() {
try {
while (true) {
move();
Thread.sleep(30);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
As the code shows, you need a custom JPanel, because you want to change the behavior of some methods like paintComponent.
However, you don't need a custom JFrame, so no need to create a class extending it.
Finally, your main class has no need to be your panel class.
Here is an example class, I moved the frame stuff from Game's constructor to this main class.
public class MainClass {
public static void main(String[] args) {
Game game = new Game();
JFrame frame = new JFrame();
frame.addKeyListener(new AL());
frame.setTitle("Game");
frame.setSize(500, 500);
frame.setResizable(true);
frame.getContentPane().add(game);
frame.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Thread t = new Thread(game);
t.start();
}
}
A JFrame is a far more complex component then you might think, for starters, it has a JRootPane as it's primary container, which contains the contentPane, JMenuBar and controls the glassPane
see How to Use Root Panes for more details.
The JFrame also has decorations (borders), these borders are painted within the confines of the window itself, the contents are then laid out within these, so the borders don't paint over then.
When you override paint of a top level container, like JFrame, there are a number of issues which you run into:
It's not double buffered, which can cause flickering as the window is updated
The other components can be painted independently of the frame (so the frame's paint method is not called), which can cause no end of issues
You can now paint beneath the frame's decorations, see Java graphic image, How to get the EXACT middle of a screen, even when re-sized and How can I set in the midst? for more details.
You're locking your self into a single use case, you can't add windows to other containers, which reduces your components re-use value
Generally speaking, from a OOP point of view, you're not actually adding any new functionality to the class (or least none which can't be generated through better approaches).
When you use something like JPanel, all other the above are no longer of concern:
They are double buffered by default
If you use a layout manager (on the content pane), the component will be laid out within the frame's decorations
The width and height of the component represent the whole viewable area
You can add this component to what ever container you want
You should also override the JPanel's getPreferredSize method and return the preferred size you want your panel to generally be, then you can use JFrame#pack to "pack" the window around it, this will make the window larger then the content area, but means you're not scratching your head wondering why you set the window to a certain size, but your component is smaller

Simple Pong Game Keyboard Input

(The game is not complete yet but nevertheless)
Using the keyboard input does not do anything, I believe this is due to KeyListener not being defined properly. Here is my code:
mainClass:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class mainClass extends JComponent{
private static ballAndGameplay ball;
private static calculateDrawPos blocks;
public static void main(String[] a) {
JFrame window = new JFrame("PONG");
window.setSize(1280,720);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainClass mc = new mainClass();
window.getContentPane().add(new mainClass());
window.setVisible(true);
ball = new ballAndGameplay(630,300,5,5);
blocks = new calculateDrawPos(false,false,false,false);
mc.addKeyListener(blocks);
while (true){
blocks.moveBlocks();
ball.moveBall();
mc.removeAll();
mc.paint(window.getGraphics());
try{
Thread.sleep(10);
}
catch (Exception e){
}
}
}
public void paint(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect (-10, -10, 1300, 740);
g.setColor(Color.WHITE);
g.fillRect (10, blocks.PlayerOneY, 25, 125); //left player
g.fillRect (1230, blocks.PlayerTwoY, 25, 125); //right player
g.fillRect (638, -10, 4, 740); //middle line
g.fillRect (ball.ballX, ball.ballY, 20, 20); //ball
}
}
calculateDrawPos:
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class calculateDrawPos extends KeyAdapter implements KeyListener {
int PlayerOneY=275;
int PlayerTwoY=275;
boolean wPressed;
boolean sPressed;
boolean upPressed;
boolean downPressed;
public calculateDrawPos (boolean a, boolean b, boolean c, boolean d) {
this.wPressed=a;
this.sPressed=b;
this.upPressed=c;
this.downPressed=d;
}
public void keyPressed(KeyEvent event) {
int keyCode = event.getKeyCode();
if (keyCode == KeyEvent.VK_W);
{
wPressed=true;
}
if (keyCode == KeyEvent.VK_S);
{
sPressed=true;
}
if (keyCode == KeyEvent.VK_UP);
{
upPressed=true;
}
if (keyCode == KeyEvent.VK_DOWN);
{
downPressed=true;
}
}
public void keyReleased(KeyEvent event) {
int keyCode = event.getKeyCode();
if (keyCode == KeyEvent.VK_W);
{
wPressed=false;
}
if (keyCode == KeyEvent.VK_S);
{
sPressed=false;
}
if (keyCode == KeyEvent.VK_UP);
{
upPressed=true;
}
if (keyCode == KeyEvent.VK_DOWN);
{
downPressed=true;
}
}
public void moveBlocks(){
if (wPressed==(true)){
PlayerOneY-=5;
}
if (sPressed==(true)){
PlayerOneY+=5;
}
if (upPressed==(true)){
PlayerTwoY-=5;
}
if (downPressed==(true)){
PlayerTwoY+=5;
}
}
}
ballAndGameplay:
import java.util.Random;
public class ballAndGameplay {
private static Random rand;
int ballX;
int ballY;
int ballXVelocity;
int ballYVelocity;
public ballAndGameplay (int a, int b, int c, int d) {
rand = new Random();
this.ballX=a;
this.ballY=b;
this.ballXVelocity=c;
this.ballYVelocity=d;
}
public void moveBall() {
boolean pointFinished = (ballX <= -20 || ballX >= 1280);
if (ballY <= 20 || ballY >= 700) {
ballYVelocity*=-1;
}
// if ((ballY >= PlayerOneY && ballY <= PlayerOneY+125 && ballX <= 35) || (ballY >= PlayerTwoY && ballY <= PlayerTwoY+125 && ballX >= 1245)){
// ballXVelocity*=-1.2;
// }
if (pointFinished==(true)){
try{
Thread.sleep(500);
}
catch (Exception e){
}
ballX=630;
ballY=300;
getBallX();
getBallY();
}
ballX+=ballXVelocity;
ballY+=ballYVelocity;
// System.out.println("ballX: "+ballX+" ballY: "+ballY+" ballXVelocity: "+ballXVelocity+" ballYVelocity: "+ballYVelocity);
}
public int getBallX(){
if (ballX != 630){
return ballXVelocity;
}
int side = rand.nextInt(2);
int number = rand.nextInt(5);
number+=4;
if (side==0){
ballXVelocity=-1*number;
}
else if (side==1){
ballXVelocity=1*number;
}
return ballXVelocity;
}
public int getBallY(){
if (ballY != 300){
return ballYVelocity;
}
int side = rand.nextInt(2);
int number = rand.nextInt(5);
number+=4;
if (side==0){
ballYVelocity=-1*number;
}
else if (side==1){
ballYVelocity=1*number;
}
return ballYVelocity;
}
}
You wrote
mainClass mc = new mainClass();
window.getContentPane().add(new mainClass());
That means that the mainClass that you added to your window isn't the same one that mc references. So all those operations you do to mc won't make any changes in your window.
You could try writing
mainClass mc = new mainClass();
window.getContentPane().add(mc);
instead.
Issues:
A KeyListener only works on a component that has current focus.
Your adding your KeyListener to a JComponent, a component that by default isn't even able to gain the focus (unlike a JButton, JTextField, and other components that typically allow keyboard interaction.)
One short term solution is to make your JComponent, the mc variable focusable by calling mc.setFocusable(true); and then giving it the system focus by calling mc.requestFocusInWindow();.
But having said this, you're still far better off using Key Bindings
Other issues:
Override and draw in the JComponent's paintComponent method not the paint method, if only to avoid the jerky graphics you'll get using paint.
Don't forget to call the super's paintComponent method in your override to erase the old ball image.
Never use a Graphics object obtained from a component by calling getGraphics() on it as the object thus obtained my become invalid or go null over time leading to invalid graphics or worse.
Never call the paint(...) or paintComponent(...) method directly as you're doing.
Instead use passive graphics as per the Swing graphics tutorials which I urge you to read.
Use a Swing Timer instead a while (true) loop since your while (true) loop risks tying up the Swing event thread, freezing your application.

Java: Filling in Graphics based on 2D array as mouse held down

So I have a JPanel that is populated by the contents of a 2D array. I have a mouse listener which changes the colour of a cell when pressed. My question is, is it possible to have the user drag the mouse over a line of cells and colour them all in succession? I have looked into mouse motion listener but this doesn't seem to help.
Any ideas?
You can use the mouseDragged() method of the MouseMotionListener in conjunction with the mousePressed() method of the MouseListener.
The mousePressed() method will handle a simple click without movement, and mouseDragged() will handle any dragging done. I combined the code I wrote for my answer to your original question here to better clarify what everything does, and a response on your other question would be very much appreciated.
package stackoverflow.answers;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class JPanelPaint {
JPanel panel;
JFrame frame;
BufferedImage image;
public JPanelPaint() {
image = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i < image.getWidth(); i++) {
for (int j=0; j < image.getHeight(); j++) {
/* I'm just initializing the image with an arbitrary color (white in this case), you can easily change this. */
image.setRGB(i, j, new Color((int)(255 ), (int)(255 ), (int)(255 )).getRGB());
}
}
frame = new JFrame("JPanel Paint");
panel = new JPanel() {
#Override
public void paint(Graphics g) {
super.paint(g);
Rectangle rect = g.getClipBounds();
g.setColor(Color.white);
g.fillRect(rect.x, rect.y, rect.width, rect.height);
for (int i = 0; i < image.getWidth(); i++) {
for (int j=0; j < image.getHeight(); j++) {
/* Set the color of the "quadpixel" to that of the original cell on the image. */
g.setColor(new Color(image.getRGB(i, j)));
g.fillRect(j*4, i*4, 4, 4);
}
}
}
};
panel.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent arg0) { }
#Override
public void mouseEntered(MouseEvent arg0) { }
#Override
public void mouseExited(MouseEvent arg0) { }
#Override
public void mousePressed(MouseEvent arg0) {
/* Y and X are swapped, just a quirk in the JRE */
/* I'm just setting the pixel with an arbitrary color (black in this case), you can easily change this. */
image.setRGB(arg0.getY() / 4, arg0.getX() / 4, new Color(0, 0, 0).getRGB());
panel.repaint();
}
#Override
public void mouseReleased(MouseEvent arg0) { }
});
panel.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent arg0) {
/* Y and X are swapped, just a quirk in the JRE */
/* I'm just setting the pixel with an arbitrary color (black in this case), you can easily change this. */
image.setRGB(arg0.getY() / 4, arg0.getX() / 4, new Color(0, 0, 0).getRGB());
panel.repaint();
}
#Override
public void mouseMoved(MouseEvent arg0) { }
});
panel.setPreferredSize(new Dimension(200, 200));
frame.add(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
panel.repaint();
}
public static void main(String[] args) {
new JPanelPaint();
}
}
You don't need the mouse listeners if you extend JPanel. Just enable mouse events then override the component's mouse event handlers. The general logic is:
if mouse pressed {
dragging = true
begin drag
}
if mouse dragged and dragging == true {
process drag
}
if mouse released and dragging == true {
dragging = false
finalize drag
}
Here is an example:
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DragTest {
// example JPanel. click and drag on it to create lines.
static class DragPanel extends JPanel {
private static final long serialVersionUID = 1L;
static class Line {
int x1, y1, x2, y2;
}
private final List<Line> lines = new ArrayList<Line>();
private Line draggedLine; // null if not dragging
public DragPanel() {
// enable mouse event processing even if no listeners are registered
enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
// draw saved lines
g.setColor(Color.WHITE);
for (Line line : lines)
g.drawLine(line.x1, line.y1, line.x2, line.y2);
// draw currently active line if there is one
if (draggedLine != null) {
g.setColor(Color.RED);
g.drawLine(draggedLine.x1, draggedLine.y1, draggedLine.x2, draggedLine.y2);
}
}
// does the work; since motion and press/release are all MouseEvent,
// we can just direct MouseEvents here from the event handler overrides
// and handle based on event ID.
private void handleMouseEvent(MouseEvent e) {
if (e.getID() == MouseEvent.MOUSE_PRESSED && e.getButton() == MouseEvent.BUTTON1) {
// begin drag by initializing a new Line at mouse position
if (draggedLine == null) {
draggedLine = new Line();
draggedLine.x1 = draggedLine.x2 = e.getX();
draggedLine.y1 = draggedLine.y2 = e.getY();
e.consume();
}
} else if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
// if drag in progress, update line endpoint
if (draggedLine != null) {
draggedLine.x2 = e.getX();
draggedLine.y2 = e.getY();
e.consume();
}
} else if (e.getID() == MouseEvent.MOUSE_RELEASED && e.getButton() == MouseEvent.BUTTON1) {
// if drag in progress, accept new line and end drag
if (draggedLine != null) {
draggedLine.x2 = e.getX();
draggedLine.y2 = e.getY();
lines.add(draggedLine);
draggedLine = null;
e.consume();
}
}
if (e.isConsumed())
repaint();
}
#Override
public void processMouseMotionEvent(MouseEvent e) {
handleMouseEvent(e); // pass to our handler, may consume event
super.processMouseMotionEvent(e); // in case there are registered listeners
}
#Override
public void processMouseEvent(MouseEvent e) {
handleMouseEvent(e); // pass to our handler, may consume event
super.processMouseEvent(e); // in case there are registered listeners
}
}
public static final void main(String[] args) {
JFrame frame = new JFrame("Panel Drag Example");
frame.getContentPane().add(new DragPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(640, 480);
frame.setVisible(true);
}
}
Extending JPanel is usually a better idea than adding listeners with inline classes because it gives you a fully self-contained reusable component.

main methods and key listener

Would anyone be able to tell me why this program says I am missing a main method? I have one at the bottom of this code.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class Collision extends JFrame
{
final int WIDTH = 900, HEIGHT = 650;
double p1Speed = .5, p2Speed = .5;
//these are the ints that represent directions
final int UP = 0, RIGHT = 1, DOWN = 2, LEFT = 3;
//these will keep track of the players directions(default = up)
int p1Direction = UP;
int p2Direction = UP;
Rectangle left = new Rectangle(0,0,WIDTH/9,HEIGHT);
Rectangle right = new Rectangle((WIDTH/9)*8,0,WIDTH/9,HEIGHT);
Rectangle top = new Rectangle(0,0,WIDTH,HEIGHT/9);
Rectangle bottom = new Rectangle(0,(HEIGHT/9)*8, WIDTH,HEIGHT/9);
Rectangle center = new Rectangle((int)((WIDTH/9)* 2.5),(int)((HEIGHT/9)*2.5),(int)
((WIDTH/9)*5),(HEIGHT/9)*4);
Rectangle obstacle = new Rectangle(WIDTH/2,(int)((HEIGHT/9)*7),WIDTH/10,HEIGHT/9);
Rectangle obstacle2 = new Rectangle(WIDTH/3,(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4);
Rectangle obstacle3 = new Rectangle(2*(WIDTH/3),(int)
((HEIGHT/9)*5),WIDTH/10,HEIGHT/4);
Rectangle obstacle4 = new Rectangle(WIDTH/3,HEIGHT/9,WIDTH/30,HEIGHT/9);
Rectangle obstacle5 = new Rectangle(WIDTH/2,(int)((HEIGHT/9)*1.5),WIDTH/30,HEIGHT/4);
Rectangle finish = new Rectangle(WIDTH/9,(HEIGHT/2)-HEIGHT/9,(int)
((WIDTH/9)*1.5),HEIGHT/70);
Rectangle p1 = new Rectangle(WIDTH/9,HEIGHT/2, WIDTH/30,WIDTH/30);
Rectangle p2 = new Rectangle(((WIDTH/9)+((int)((WIDTH/9)*1.5)/2)),(HEIGHT/2)+
(HEIGHT/10),WIDTH/30,WIDTH/30);
public Collision()
{
//the following code creates the JFrame
super("Radical Racing");
setSize(WIDTH,HEIGHT);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
//start the inner class (which works on it's own because it is a thread)
Move1 m1 = new Move1();
Move2 m2 = new Move2();
m1.start();
m2.start();
}
public void paint(Graphics g)
{
super.paint(g);
//draw the bckround for the racetrack
g.setColor(Color.DARK_GRAY);
g.fillRect(0,0,WIDTH,HEIGHT);
//When we drawthe border will be green
g.setColor(Color.GREEN);
//the following rectangle is the start line for the outer player
Rectangle lineO = new
Rectangle(WIDTH/9,HEIGHT/2,(int)((WIDTH/9)*1.5)/2,HEIGHT/140);
//the following rctangle is the start line for the inner player
Rectangle lineI = new
Rectangle(((WIDTH/9)+((int)((WIDTH/9)*1.5)/2)),(HEIGHT/2)+(HEIGHT/10),
(int)((WIDTH/9)*1.5)/2,HEIGHT/140);
//now using the rectangles, draw it
g.fillRect(left.x,left.y,left.width,left.height);
g.fillRect(right.x,right.y,right.width,right.height);
g.fillRect(top.x,top.y,top.width,top.height);
g.fillRect(bottom.x,bottom.y,bottom.width,bottom.height);
g.fillRect(center.x,center.y,center.width,center.height);
g.fillRect(obstacle.x,obstacle.y,obstacle.width,obstacle.height);
g.fillRect(obstacle2.x,obstacle2.y,obstacle2.width,obstacle2.height);
g.fillRect(obstacle3.x,obstacle3.y,obstacle3.width,obstacle3.height);
g.fillRect(obstacle4.x,obstacle4.y,obstacle4.width,obstacle4.height);
g.fillRect(obstacle5.x,obstacle5.y,obstacle5.width,obstacle5.height);
//set the starting line color
g.setColor(Color.WHITE);
//the draw the starting line
g.fillRect(lineO.x,lineO.y,lineO.width,lineO.height);
g.fillRect(lineI.x,lineI.y,lineI.width,lineI.height);
//set the color of the finish line to yellow
g.setColor(Color.YELLOW);
g.fillRect(finish.x,finish.y,finish.width,finish.height);
//set the color to blue for p1
g.setColor(Color.BLUE);
//now draw the actual player
g.fill3DRect(p1.x,p1.y,p1.width,p1.height,true);
//set the color to red for p2
g.setColor(Color.red);
//now draw the actual player
g.fill3DRect(p2.x,p2.y,p2.width,p2.height,true);
}
private class Move1 extends Thread implements KeyListener
{
public void run()
{
//add the code to make the KeyListener "wake up"
addKeyListener(this);
//now, put the code should all be in an infinite loop, so the process repeats.
while(true)
{
try
{
//first refresh the screen:
repaint();
//check to see if the car hits the outside of the walls.
//If so make it slow it's speed by setting it's speed to .4.
if(p1.intersects(left) || p1.intersects(right) ||
p1.intersects(top) || p1.intersects(bottom) ||
p1.intersects(obstacle) || p1.intersects(obstacle2) ||
p1.intersects(p2) || p1.intersects(obstacle3) ||
p1.intersects(obstacle4) || p1.intersects(obstacle5))
{
p1Speed = -4;
}
if(p1.intersects(center))
{
p1Speed = -2.5;
}
//increase speed a bit
if(p1Speed<=5)
p1Speed+=.2;
//these will move the player based on direction
if(p1Direction == UP)
{
p1.y-=(int)p1Speed;
}
if(p1Direction ==DOWN)
{
p1.y+=(int)p1Speed;
}
if(p1Direction == LEFT)
{
p1.x-=(int)p1Speed;
}
if(p1Direction == RIGHT)
{
p1.x+=(int)p1Speed;
}
//This delays the refresh rate
Thread.sleep(75);
}
catch(Exception e)
{//if there is an exception (an error), exit the loop
break;
}
}
}
//You must also implement this method from Key Listener
public void keyPressed(KeyEvent event)
{
}
//You must also implement this method from key listener
public void keyReleased(KeyEvent event)
{
}
//You must also implement this method from key listener
public void keyTyped(KeyEvent event)
{
if(event.getKeyChar()=='a')
{
p1Direction = LEFT;
}
if(event.getKeyChar()=='s')
{
p1Direction = DOWN;
}
if(event.getKeyChar()=='d')
{
p1Direction = RIGHT;
}
if(event.getKeyChar()=='w')
{
p1Direction = UP;
}
}
}
private class Move2 extends Thread implements KeyListener
{
public void run()
{
//add the code to make the key listener wake up
addKeyListener(this);
//now this should all be in an infinite loop so that the process repeats
while(true)
{
try
{
//first refresh the screen
repaint();
//check to see if the car hits the outside walls.
//if so make it slow its speed by setting it's speed to -4.
if(p2.intersects(left) || p2.intersects(right) ||
p2.intersects(top) || p2.intersects(bottom) ||
p2.intersects(obstacle) || p2.intersects(obstacle2) ||
p1.intersects(p2))
{
p2Speed = -4;
}
if(p2.intersects(center))
{
p2Speed = -2.5;
}
//increase speed a bit
if(p2Speed<=5)
p2Speed = .2;
//these will move the player based off direction
if(p2Direction == UP)
{
p2.y-=(int)p2Speed;
}
if(p2Direction ==DOWN)
{
p2.y+=(int)p2Speed;
}
if(p2Direction == LEFT)
{
p2.x-=(int)p2Speed;
}
if(p2Direction == LEFT)
{
p2.x+=(int)p2Speed;
}
//this delays the refresh rate:
Thread.sleep(75);
}
catch(Exception e)
{
//if there is an exception, exit the loop.
break;
}
}
}
//you must also implement this method from key listener
public void keyPressed(KeyEvent event)
{
}
public void keyReleased(KeyEvent event)
{
}
public void keyTyped(KeyEvent event)
{
if(event.getKeyChar()=='j')
{
p2Direction = LEFT;
}
if(event.getKeyChar()=='k')
{
p2Direction = DOWN;
}
if(event.getKeyChar()=='l')
{
p2Direction = RIGHT;
}
if(event.getKeyChar()=='i')
{
p2Direction = UP;
}
}
//This starts the program by calling the constructor:
public static void main(String [] args)
{
new Collision();
}
}
KeyListeners only work if the component listened to has the focus, and often KeyListeners fail because this is not so. So one thing to do is to test this, and if the component has lost the focus than do things to correct this.
But having said this, I have to ask what book you're using, since in general, you want to avoid using KeyListeners with Swing applications in favor of Key Bindings. Also, it is usually not recommended to draw directly in a JFrame, so you may wish to use a different book.

Categories