This question already has answers here:
None of the event occurs
(3 answers)
Closed 8 years ago.
For some reason my program doesn't detect when I press a key even though it should be fine.
This is my code:
import javax.swing.*;
public class Frame {
public static void main(String args[]) {
Second s = new Second();
JFrame f = new JFrame();
f.add(s);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Bouncing Ball");
f.setSize(600, 400);
}
}
This is the Second class:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import javax.swing.*;
public class Second extends JPanel implements ActionListener, KeyListener {
Timer t = new Timer(5, this);
double x = 0, y = 0, velX =0 , velY = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Rectangle2D circle = new Rectangle2D.Double(x, y, 40, 40);
g2.fill(circle);
t.start();
}
public void actionPerformed(ActionEvent e) {
x += velX;
y += velY;
repaint();
}
public void up() {
velY = -1.5;
velX = 0;
}
public void down() {
velY = 1.5;
velX = 0;
}
public void keyPressed(KeyEvent e) {
int KeyCode = e.getKeyCode();
if (KeyCode == KeyEvent.VK_Z) {
up();
}
if (KeyCode == KeyEvent.VK_S) {
down();
}
}
public void keyTyped(KeyEvent e){
}
public void keyReleased(KeyEvent e){
}
}
How can I solve this problem?
The reason the timer doesn't appear to work is because, velX and velY are equals to 0, so, it doesn't increment anything. If you give them a value, it will animate.
The reason the Keys won't work is
because you haven't registered the KeyListener to the panel.
you need to setfocusable(true).
You need to call repaint() in the either the up() down() methods or in the keyPressed() method.
You need to increment/decrement the y value in the up() and down() methods.
Add the below constructor, add the repaint() to the keyPressed() and increment/decrement correctly and it works
public Second(){
setFocusable(true);
addKeyListener(this);
}
Add the above constructor. And the repaint in the keyPressed
public void keyPressed(KeyEvent e) {
int KeyCode = e.getKeyCode();
if (KeyCode == KeyEvent.VK_Z) {
up();
repaint();
}
if (KeyCode == KeyEvent.VK_S) {
down();
repaint();
}
}
Increment/Decrement
public void up() {
y -= 10;
}
public void down() {
y += 10;
}
Though this may work, it is recommended to use key bindings.
See How to use Key Bindings | The complete Creating a GUI with Swing trail
For testing purposes, add a listener to the JFrame and see if you get any response there. If you do, then it means that the JFrame isn't passing the events down to the Second, probably because the Second doesn't have focus.
You could also try calling requestFocusInWindow(): http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html
A component generally gains the focus when the user clicks it, or when the user tabs between components, or otherwise interacts with a component. A component can also be given the focus programmatically, such as when its containing frame or dialog-box is made visible. This code snippet shows how to give a particular component the focus every time the window gains the focus:
//Make textField get the focus whenever frame is activated.
> f.addWindowFocusListener(new WindowAdapter() {
> public void windowGainedFocus(WindowEvent e) {
> s.requestFocusInWindow();
> } });
I would also recommend using more descriptive variables than s, f, and a more descriptive class name than Second.
Related
hi im trying to make a rectangle move up and down on key press in jframe.
but the rectangle only goes down when i press the up or down arrow key and it does not stop. and i cant see where i have made a mistake.
i don't think the mistake is in file one but as said, i cant find it so it maybe is.
file 1
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class test{
public static void main (String[] arg) {
JFrame window = new JFrame();
test2 t2 = new test2();
window.add(t2);
window.setSize(1000,1000);
window.setTitle("TEST");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
}
file 2
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class test2 extends JPanel implements ActionListener, KeyListener{
Timer t = new Timer(5, this);
double x = 0, y = 0, velx = 0, vely = 0;
public test2() {
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Rectangle((int)x, (int)y, 20, 40));
}
public void actionPerformed(ActionEvent e) {
repaint();
x += velx;
y += vely;
}
public void up() {
vely = -1.5;
velx = 0;
}
public void down() {
vely = 1.5;
velx = 0;
}
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP); {
up();
}
if (code == KeyEvent.VK_DOWN); {
down();
}
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e){}
}
Your logic is not very optimal. You should have your code more like this:
/** DELETE THIS METHOD!
public void actionPerformed(ActionEvent e) {
repaint();
x += velx;
y += vely;
}**/
private static final double MOVEMENT = 1.5;
public void up() {
x += -MOVEMENT; // Mind the - in front of MOVEMENT to negate the value.
// No need to change y if it does not change at all
repaint() // Repaint _after_ you changed the coordinates
}
public void down() {
x += MOVEMENT; // Mind that there is no - infront of this MOVEMENT.
// No need to change y if it does not change at all
repaint() // Repaint _after_ you changed the coordinates
}
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP); {
up();
}
if (code == KeyEvent.VK_DOWN); {
down();
}
}
You miss calling repaint() onYour JPanel after changing the position of x,y;
Also note that your events will only trigger twice (OnKeyDown and OnKeyUp).
I'm trying to make a program in java that involves making an object move constantly from a single key press. Think Pacman, where you press up once and Pacman continues to go up until you press another key. I want to keep the code simple if possible. My original movement (one keypress = one movement) is like this:
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_A){
x -= 5;
}
if(keyCode == e.VK_D){
x += 5;
}
if(keyCode == e.VK_W){
y -= 5;
}
if(keyCode == e.VK_S){
y += 5;
}
}
The x and y in values are the position of an oval. This works perfectly, but I want it to keep moving after I press the key only once, instead of having to hold it to keep the movement going. I tried a while loop with a boolean parameter that moves while true and doesn't while false, but as soon as I activate the loop, it freezes the program. Here's an example of that bit of code:
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT && moveL==false){
moveL=true;
moveR=false;
moveU=false;
moveD=false;
while(moveL){
x--;
}
}
Please help me figure this out, I've been trying and looking around for days now. I appreciate any help you guys can give. Thanks.
The basic concept revolves around this idea of a "delta" or "change" value. This value is then applied to the state you want to change by either incrementing or decrementing the state value by it.
Because of the nature of Swing, you can't block the Event Dispatching Thread, otherwise you end up preventing from processing incoming events (such as paint and key events).
Equally, you should never try and update any UI component (or state variable that might effect the UI) from any thread other then the EDT.
While there are tricks you can apply to facilitate these requirements, the simplest is to use a javax.swing.Timer, which triggers a actionPerformed event on a regular bases within the EDT.
When this occurs you "update" all the elements by the prescribed amount and repaint the screen.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PacManTest {
public static void main(String[] args) {
new PacManTest();
}
public PacManTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new MazePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PacMan {
private int x;
private int y;
private int deltaX;
private int deltaY;
private BufferedImage sprite;
public PacMan() {
try {
sprite = ImageIO.read(new File("PacMan.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void move(int x, int y) {
deltaX = x;
deltaY = y;
}
public void update(MazePane pane) {
x += deltaX;
y += deltaY;
if (x + sprite.getWidth() > pane.getWidth()) {
x = pane.getWidth() - sprite.getWidth();
} else if (x < 0) {
x = 0;
}
if (y + sprite.getHeight() > pane.getHeight()) {
y = pane.getHeight() - sprite.getHeight();
} else if (y < 0) {
y = 0;
}
}
public void paint(MazePane pane, Graphics2D g2d) {
Graphics2D g = (Graphics2D) g2d.create();
float angle = 0;
if (deltaX != 0) {
angle = deltaX > 0 ? 0 : 180;
} else if (deltaY != 0) {
angle = deltaY > 0 ? 90 : 270;
}
AffineTransform t = new AffineTransform();
t.translate(x, y);
t.rotate(Math.toRadians(angle), sprite.getWidth() / 2, sprite.getHeight() / 2);
g.setTransform(t);
g.drawImage(sprite, 0, 0, pane);
g.dispose();
}
}
public class MazePane extends JPanel {
private PacMan pacMan;
public MazePane() {
pacMan = new PacMan();
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pacMan.update(MazePane.this);
repaint();
}
});
timer.start();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down");
am.put("left", new MoveAction(pacMan, -4, 0));
am.put("right", new MoveAction(pacMan, 4, 0));
am.put("up", new MoveAction(pacMan, 0, -4));
am.put("down", new MoveAction(pacMan, 0, 4));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
pacMan.paint(this, g2d);
g2d.dispose();
}
public class MoveAction extends AbstractAction {
private int deltaX;
private int deltaY;
private PacMan pacMan;
public MoveAction(PacMan pacMan, int deltaX, int deltaY) {
this.deltaX = deltaX;
this.deltaY = deltaY;
this.pacMan = pacMan;
}
#Override
public void actionPerformed(ActionEvent e) {
pacMan.move(deltaX, deltaY);
}
}
}
}
I would also recommend that you take the time to learn about Key Bindings, KeyListener suffer from focus issues, which key bindings are capable of addressing...
You need to process the move in a separate thread. I.e.:
public class Pacman implements Runnable
{
public void run(){
//moving code, i.e. in a while loop
//every move will notify the EDT:
SwingUtilities.invokeLater(new Runnable(){
public void run(){
//update the Swing here - i.e. move Pacman
}
}
}
public void startMoving(){
new Thread(this).start();
}
//more methods to set speed, direction, etc...
}
Then you keep a reference to an instance of Pacman class in your Gui class and respond to various key presses by changing pacman's parameters:
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT){
pacman.newDirection(LEFT); //for exmaple, enum with direction LEFT, RIGHT, UP, DOWN...
}
//etc... more logic
}
I'm trying to make a program in java that involves making an object move constantly from a single key press. Think Pacman, where you press up once and Pacman continues to go up until you press another key. I want to keep the code simple if possible. My original movement (one keypress = one movement) is like this:
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_A){
x -= 5;
}
if(keyCode == e.VK_D){
x += 5;
}
if(keyCode == e.VK_W){
y -= 5;
}
if(keyCode == e.VK_S){
y += 5;
}
}
The x and y in values are the position of an oval. This works perfectly, but I want it to keep moving after I press the key only once, instead of having to hold it to keep the movement going. I tried a while loop with a boolean parameter that moves while true and doesn't while false, but as soon as I activate the loop, it freezes the program. Here's an example of that bit of code:
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT && moveL==false){
moveL=true;
moveR=false;
moveU=false;
moveD=false;
while(moveL){
x--;
}
}
Please help me figure this out, I've been trying and looking around for days now. I appreciate any help you guys can give. Thanks.
The basic concept revolves around this idea of a "delta" or "change" value. This value is then applied to the state you want to change by either incrementing or decrementing the state value by it.
Because of the nature of Swing, you can't block the Event Dispatching Thread, otherwise you end up preventing from processing incoming events (such as paint and key events).
Equally, you should never try and update any UI component (or state variable that might effect the UI) from any thread other then the EDT.
While there are tricks you can apply to facilitate these requirements, the simplest is to use a javax.swing.Timer, which triggers a actionPerformed event on a regular bases within the EDT.
When this occurs you "update" all the elements by the prescribed amount and repaint the screen.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PacManTest {
public static void main(String[] args) {
new PacManTest();
}
public PacManTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new MazePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PacMan {
private int x;
private int y;
private int deltaX;
private int deltaY;
private BufferedImage sprite;
public PacMan() {
try {
sprite = ImageIO.read(new File("PacMan.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void move(int x, int y) {
deltaX = x;
deltaY = y;
}
public void update(MazePane pane) {
x += deltaX;
y += deltaY;
if (x + sprite.getWidth() > pane.getWidth()) {
x = pane.getWidth() - sprite.getWidth();
} else if (x < 0) {
x = 0;
}
if (y + sprite.getHeight() > pane.getHeight()) {
y = pane.getHeight() - sprite.getHeight();
} else if (y < 0) {
y = 0;
}
}
public void paint(MazePane pane, Graphics2D g2d) {
Graphics2D g = (Graphics2D) g2d.create();
float angle = 0;
if (deltaX != 0) {
angle = deltaX > 0 ? 0 : 180;
} else if (deltaY != 0) {
angle = deltaY > 0 ? 90 : 270;
}
AffineTransform t = new AffineTransform();
t.translate(x, y);
t.rotate(Math.toRadians(angle), sprite.getWidth() / 2, sprite.getHeight() / 2);
g.setTransform(t);
g.drawImage(sprite, 0, 0, pane);
g.dispose();
}
}
public class MazePane extends JPanel {
private PacMan pacMan;
public MazePane() {
pacMan = new PacMan();
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pacMan.update(MazePane.this);
repaint();
}
});
timer.start();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down");
am.put("left", new MoveAction(pacMan, -4, 0));
am.put("right", new MoveAction(pacMan, 4, 0));
am.put("up", new MoveAction(pacMan, 0, -4));
am.put("down", new MoveAction(pacMan, 0, 4));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
pacMan.paint(this, g2d);
g2d.dispose();
}
public class MoveAction extends AbstractAction {
private int deltaX;
private int deltaY;
private PacMan pacMan;
public MoveAction(PacMan pacMan, int deltaX, int deltaY) {
this.deltaX = deltaX;
this.deltaY = deltaY;
this.pacMan = pacMan;
}
#Override
public void actionPerformed(ActionEvent e) {
pacMan.move(deltaX, deltaY);
}
}
}
}
I would also recommend that you take the time to learn about Key Bindings, KeyListener suffer from focus issues, which key bindings are capable of addressing...
You need to process the move in a separate thread. I.e.:
public class Pacman implements Runnable
{
public void run(){
//moving code, i.e. in a while loop
//every move will notify the EDT:
SwingUtilities.invokeLater(new Runnable(){
public void run(){
//update the Swing here - i.e. move Pacman
}
}
}
public void startMoving(){
new Thread(this).start();
}
//more methods to set speed, direction, etc...
}
Then you keep a reference to an instance of Pacman class in your Gui class and respond to various key presses by changing pacman's parameters:
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT){
pacman.newDirection(LEFT); //for exmaple, enum with direction LEFT, RIGHT, UP, DOWN...
}
//etc... more logic
}
I am starting out with Java and I have a problem. When people click "a" on the java applet, I want it to draw a yellow rectangle and if they press anything else it draws a black rectangle but nothing happens.
import java.awt.*;
import java.applet.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
public class guitarGame extends Applet implements ActionListener, KeyListener{
Timer timer = new Timer (1000, this);
String s = "";
char a;
int selection;
public void keyReleased(KeyEvent ae){}
public void keyPressed(KeyEvent ae){}
public void keyTyped(KeyEvent ae){
a = ae.getKeyChar();
}
public void init(){
addKeyListener(this);
}
public void actionPerformed (ActionEvent ae)
{
if (a == a)
{
selection = 1;
}
else{
selection = 2;
}
}
public void paint (Graphics g)
{
if (selection == 1){
g.setColor(Color.YELLOW);
g.fillRect(100,100,100,100);
}
if (selection == 2){
g.setColor(Color.YELLOW);
g.fillRect(100,100,100,100);
}
repaint();
}
}
Any help?
You are not doing anything with your KeyListener methods. Your ActionListener will never be called as it hasnt been registered with any component.
public void keyPressed(KeyEvent ae){
char keyChar = ae.getKeyChar();
if (keyChar == 'a' ) {
selection = 1;
} else {
selection = 2;
}
repaint();
}
Some suggestions:
Don't call repaint inside paint - This will cause the latter to loop indefinitely
Use enums rather than magic numbers for paint selection.
Call super.paint(g)
Consider using Swing which has much better performance over the old heavyweight AWT.
This has been making me want to tear out my hair all day. I'm trying to make it so when I press the right-arrow key, my speed will go to 10. I know that my methods that make my sprite move work, because if I set a value beforehand, it moves across the screen. It's the KeyListener that isn't doing anything:
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
public class Sprite implements KeyListener{
public Image player = Toolkit.getDefaultToolkit().getImage("player.png");
int x, y, dx, dy;
public void doInit(){
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(600, 400);
window.setLocationRelativeTo(null);
window.getContentPane().add(new ImageDraw());
window.setVisible(true);
window.setIgnoreRepaint(true);
window.createBufferStrategy(2);
window.getContentPane().addKeyListener(this);
}
public Image getSpriteHandle(){
return player;
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_RIGHT){
dx = 10;
}
} //end keyPressed
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_RIGHT){
dx = 0;
}
}
public void keyTyped(KeyEvent arg0) {
}
public int moveX(){
return dx;
}
} //end class
Please help me!
It's the KeyListener that isn't doing anything
You should NOT be using a KeyListener.
Swing was designed to be used with Key Bindings. You can map an Action to a KeyStroke even when a component doesn't have focus.