How to change value of integer on keyPress - java

I have a JLabel which has a string that has an integer, which starts at 0. I want it so that way, every time a key (like "w") is pressed, the integer goes up by 1. I have searched the web far and wide, but I have returned nothing (maybe because of my wording). Here's the code:
public void keyTyped(KeyEvent e) {
//keyTyped = Invoked when a key is typed. Uses KeyChar, char output
switch(e.getKeyChar()) {
case 'a': label.setLocation(label.getX()-10, label.getY());
for(int coins=0; coins<1;coins++) {
coins = coins + 1;
}
break;
case 'w': label.setLocation(label.getX(), label.getY()-10);
for(int coins=0; coins<1;coins++) {
coins = coins + 1;
}
break;
case 's': label.setLocation(label.getX(), label.getY()+10);
for(int coins=0; coins<1;coins++) {
coins = coins + 1;
}
break;
case 'd': label.setLocation(label.getX()+10, label.getY());
for(int coins=0; coins<1;coins++) {
coins = coins + 1;
}
break;
}
}
Maybe it is what I wrote in the code and it won't change? I didn't see similar questions like mine.

See How to Use Key Bindings for example
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.border.EmptyBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel coinLabel;
private int coins;
public TestPane() {
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(32, 32, 32, 32));
coinLabel = new JLabel("0");
add(coinLabel);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
CoinAction.Observer observer = new CoinAction.Observer() {
#Override
public void coinDidChange(CoinAction action, int delta) {
coins += delta;
coinLabel.setText(Integer.toString(coins));
}
};
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "Pressed.Up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "Pressed.Down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "Pressed.Left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "Pressed.Right");
am.put("Pressed.Up", new CoinAction(1, observer));
am.put("Pressed.Down", new CoinAction(-1, observer));
am.put("Pressed.Left", new CoinAction(10, observer));
am.put("Pressed.Right", new CoinAction(-10, observer));
}
}
public class CoinAction extends AbstractAction {
public interface Observer {
public void coinDidChange(CoinAction action, int delta);
}
private int delta;
private Observer observer;
public CoinAction(int delta, Observer observer) {
this.delta = delta;
this.observer = observer;
}
public int getDelta() {
return delta;
}
#Override
public void actionPerformed(ActionEvent e) {
observer.coinDidChange(this, getDelta());
}
}
}

Related

Java KeyBindings stop working after a few seconds

I'm trying to move from Java KeyListeners to KeyBindings for animating but they work for a few seconds and then completely stop. I'm printing messages to the console when the actions fire, and those messages stop, so it's not just the painting that isn't working, it's the firing of the actions when the keys are pressed.
My class extends JFrame, and I just add a JPanel to it, and add a JLabel to the JPanel. I use flags toggled by the Actions to indicate how the JLabel should move, and I use the JFrame's actionPerformed method to check the state of the flags and adjust the JLabel's location.
I've tried adding JComponent.WHEN_IN_FOCUSED_WINDOW inside the getInputMap method, but it made no difference.
Here's the code:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class KeyBindingTest extends JFrame implements ActionListener {
long counter = 0;
int speed = 5;
boolean isUp = false, isDown = false, isLeft = false, isRight = false;
JLabel j = new JLabel();
JPanel p = new JPanel();
Timer t;
Action upPressed = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("up on");
isUp = true;
}
};
Action upReleased = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
isUp = false;
System.out.println("up off");
}
};
Action downPressed = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("down on");
isDown = true;
}
};
Action downReleased = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("down off");
isDown = false;
}
};
Action leftPressed = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("left on");
isLeft = true;
}
};
Action leftReleased = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("left off");
isLeft = false;
}
};
Action rightPressed = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("right on");
isRight = true;
}
};
Action rightReleased = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("right off");
isRight = false;
}
};
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
// The try/catch block prevents errors from crashing the program
try {
KeyBindingTest window = new KeyBindingTest(); // Create and setup the main game window
window.run(); // show the new window
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void run() {
this.setBounds(640, 400, 640, 400);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
p.setBounds(0, 0, this.getWidth(), this.getHeight());
p.setVisible(true);
p.setBackground(Color.blue);
p.setOpaque(true);
p.setFocusable(true);
p.setLayout(null);
j.setBounds(320, 200, 10, 10);
j.setVisible(true);
j.setBackground(Color.red);
j.setOpaque(true);
this.add(p);
p.add(j);
p.requestFocusInWindow();
setupKeyBindings();
t = new Timer(1000 / 40, this);
t.start();
}
private void setupKeyBindings() {
p.getInputMap().put(KeyStroke.getKeyStroke("W"), "moveUp");
p.getActionMap().put("moveUp", upPressed);
p.getInputMap().put(KeyStroke.getKeyStroke("released W"), "stopUp");
p.getActionMap().put("stopUp", upReleased);
p.getInputMap().put(KeyStroke.getKeyStroke("S"), "moveDown");
p.getActionMap().put("moveDown", downPressed);
p.getInputMap().put(KeyStroke.getKeyStroke("released S"), "stopDown");
p.getActionMap().put("stopDown", downReleased);
p.getInputMap().put(KeyStroke.getKeyStroke("A"), "moveLeft");
p.getActionMap().put("moveLeft", leftPressed);
p.getInputMap().put(KeyStroke.getKeyStroke("released A"), "stopLeft");
p.getActionMap().put("stopLeft", leftReleased);
p.getInputMap().put(KeyStroke.getKeyStroke("D"), "moveRight");
p.getActionMap().put("moveRight", rightPressed);
p.getInputMap().put(KeyStroke.getKeyStroke("released D"), "stopRight");
p.getActionMap().put("stopRight", rightReleased);
}
#Override
public void actionPerformed(ActionEvent e) {
counter++;
System.out.println(counter);
if (isUp) {
j.setLocation(j.getX(), j.getY() - speed);
}
if (isDown) {
j.setLocation(j.getX(), j.getY() + speed);
}
if (isLeft) {
j.setLocation(j.getX() - speed, j.getY());
}
if (isRight) {
j.setLocation(j.getX() + speed, j.getY());
}
repaint();
}
}
This is a personal thing, but, you will generally have less issues if you use something like KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false) over
KeyStroke.getKeyStroke("W")
The equivalent for KeyStroke.getKeyStroke("released W") would be KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true)
I have been back and forward through your example, I've tried replacing KeyStroke.getKeyStroke("W") with KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false) and it's equivalents; I've tried replacing the boolean flags with a Set and I still have the same issue
I then went and threw away your code and started with a new project. First I tried a custom painting route, and that worked fine. I then tried a component based route and that worked ... đŸ˜“
So, while I still don't have an "answer" for why it's not working, I do have an example which does...
Example
And because I actually had test my suggestions...
import com.sun.glass.events.KeyEvent;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public enum Input {
UP, DOWN, LEFT, RIGHT
}
public class TestPane extends JPanel {
private Set<Input> inputs = new HashSet<>();
private int delta = 4;
private JLabel label;
public TestPane() {
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "Up.pressed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "Up.relesed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "Down.pressed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), "Down.relesed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "Left.pressed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "Left.relesed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "Right.pressed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "Right.relesed");
actionMap.put("Up.pressed", new InputAction(Input.UP, true));
actionMap.put("Up.relesed", new InputAction(Input.UP, false));
actionMap.put("Down.pressed", new InputAction(Input.DOWN, true));
actionMap.put("Down.relesed", new InputAction(Input.DOWN, false));
actionMap.put("Left.pressed", new InputAction(Input.LEFT, true));
actionMap.put("Left.relesed", new InputAction(Input.LEFT, false));
actionMap.put("Right.pressed", new InputAction(Input.RIGHT, true));
actionMap.put("Right.relesed", new InputAction(Input.RIGHT, false));
setLayout(null);
label = new JLabel();
label.setBackground(Color.RED);
label.setOpaque(true);
label.setBounds(0, 0, 10, 10);
add(label);
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int xPos = label.getX();
int yPos = label.getY();
if (inputs.contains(Input.UP)) {
yPos -= delta;
}
if (inputs.contains(Input.DOWN)) {
yPos += delta;
}
if (inputs.contains(Input.LEFT)) {
xPos -= delta;
}
if (inputs.contains(Input.RIGHT)) {
xPos += delta;
}
if (xPos < 0) {
xPos = 0;
} else if (xPos + 10 > getWidth()) {
xPos = getWidth() - 10;
}
if (yPos < 0) {
yPos = 0;
} else if (yPos + 10 > getHeight()) {
yPos = getHeight() - 10;
}
label.setLocation(xPos, yPos);
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
// protected void paintComponent(Graphics g) {
// super.paintComponent(g);
// Graphics2D g2d = (Graphics2D) g.create();
// g2d.setColor(Color.RED);
// g2d.drawRect(xPos, yPos, 10, 10);
// g2d.dispose();
// }
public class InputAction extends AbstractAction {
private Input input;
private boolean pressed;
public InputAction(Input input, boolean pressed) {
this.input = input;
this.pressed = pressed;
}
#Override
public void actionPerformed(ActionEvent e) {
if (pressed) {
inputs.add(input);
} else {
inputs.remove(input);
}
}
}
}
}
A side note...
This "type" of question is getting asked a lot lately, I assume it's some kind of class assignment, as we've seen a number of variants of this style of code. As we've repeatedly advised, using components in this way is ill-advised, they aren't really designed for this kind of thing. You will get better (and easier) results using a custom painting route, as demonstrated in Make an JLabel move with Key Bidings

JButton doesn't show up in JFrame

I'm currently working on a schoolproject, where I have to code the game snake. Now I`m finished with the biggest part and tryed to make the game menue. I tryed to place a JButton for starting the game (startPlay). However, the button won't show up and I can't figure out why. Can someone help? Thanks in advance!!
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;
public class Main extends JPanel implements ActionListener, KeyListener{
public static int field[][];
public static GenerateField genField;
public static Snake snake;
public static GenerateFood food;
public static GenerateBarrier barrier;
public int difficultness;
public static int widthField;
public static int heightField;
public static TimerTask move, genBarriers;
public static Timer snakeTimer, barrierTimer;
public JButton startPlay;
public static boolean gameStarted;
public Main ()
{
startPlay = new JButton("Starte Spiel");
startPlay.setBounds(0,0,300,200);
startPlay.addActionListener(this);
add(startPlay);
difficultness = 15;
gameStarted = false;
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
widthField = 150;
heightField = 95;
genField = new GenerateField();
snake = new Snake();
food = new GenerateFood();
barrier = new GenerateBarrier();
barrierTimer = new Timer("Timer");
snakeTimer = new Timer("Timer");
genBarriers = new TimerTask() {
#Override
public void run() {
barrier.clearBarrier();
barrier.multiSpawnBarrier(difficultness);
}
};
move = new TimerTask()
{
public void run()
{
if(GenerateField.inGame)
{
snake.moveSnake();
repaint();
}
}
};
}
private static void startGame()
{
genField.generateField();
field = genField.getField();
snake.generateSnake(40, 75);
food.spawnFood();
snakeTimer.schedule(move,0,50);
barrierTimer.schedule(genBarriers, 0, 25000);
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(1520,1000);
frame.getContentPane().add(new Main());
frame.setLocationRelativeTo(null);
frame.setBackground(Color.LIGHT_GRAY);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
#Override
public void paint(Graphics g)
{
if(gameStarted) {
for (int iy = 0; iy < heightField; iy++) {
for (int ix = 0; ix < widthField; ix++) {
//Zeichnet schwarzen Hintergrund
if (genField.field[iy][ix] == 0) {
g.setColor(Color.BLACK);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
//Zeichnet die Grenze an den Rändern
if (genField.field[iy][ix] == 1) {
g.setColor(Color.red);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
//Zeichnet die Schlange
if (genField.field[iy][ix] == 2) {
g.setColor(Color.green);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
//Zeichnet das "Futter"
if (genField.field[iy][ix] == 3) {
g.setColor(Color.orange);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
//Zeichte die Hindernisse
if (genField.field[iy][ix] == 4) {
g.setColor(Color.blue);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
}
}
}
}
#Override
public void actionPerformed(ActionEvent e)
{
startPlay.setVisible(false);
startGame();
gameStarted = true;
}
#Override
public void keyPressed (KeyEvent e)
{
int code = e.getKeyCode();
if ( code == KeyEvent.VK_LEFT)
{
if (snake.mRight == false)
{
snake.mLeft = true;
snake.mRight = false;
snake.mUp = false;
snake.mDown = false;
}
}
if ( code == KeyEvent.VK_RIGHT)
{
if (snake.mLeft == false)
{
snake.mLeft = false;
snake.mRight = true;
snake.mUp = false;
snake.mDown = false;
}
}
if ( code == KeyEvent.VK_UP)
{
if (snake.mDown == false)
{
snake.mLeft = false;
snake.mRight = false;
snake.mUp = true;
snake.mDown = false;
}
}
if ( code == KeyEvent.VK_DOWN)
{
if (snake.mUp == false)
{
snake.mLeft = false;
snake.mRight = false;
snake.mUp = false;
snake.mDown = true;
}
}
}
#Override
public void keyReleased(KeyEvent e)
{
}
#Override
public void keyTyped(KeyEvent e)
{
}
}
Immediate Problem
The over use of static highlights issues with your design. static is not your friend, you should use it sparingly and wisely.
You're trying to put all your eggs in single basket. This is just going to make the state management harder to handle.
Instead, start by separating your menu and game into separate classes and managing them independently of each other.
This then allows you to use a CardLayout to manage the navigation between the different views.
The following is simple example to demonstrate how you might use CardLayout to perform decoupled navigation
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
CardLayout cardLayout = new CardLayout();
JPanel base = new JPanel(cardLayout);
NavigationController controller = new NavigationController() {
#Override
public void show(Screen screen) {
cardLayout.show(base, screen.name());
}
};
base.add(new MainMenuPane(controller), Screen.MENU.name());
base.add(new GamePane(controller), Screen.GAME.name());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(base);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public enum Screen {
MENU, GAME;
}
public interface NavigationController {
public void show(Screen scren);
}
public class MainMenuPane extends JPanel {
public MainMenuPane(NavigationController controller) {
setLayout(new GridBagLayout());
JButton start = new JButton("Start");
add(start);
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
controller.show(Screen.GAME);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class GamePane extends JPanel {
private NavigationController controller;
public GamePane(NavigationController controller) {
this.controller = controller;
setLayout(new GridBagLayout());
add(new JLabel("Ready Player One"));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Every thing else you'll need to fix
Don't use KeyListener, use Key bindings instead, they will fix the focus related issues in a more reliable way
You're violating the requirements of the paint chain, which is part of your immediate problem - See Performing Custom Painting and Painting in Swing for more details about how painting works and how you should work with it
Swing is single thread AND not thread safe - see Concurrency in Swing for more details. Essentially the use of java.util.Timer is running the risk of dirty read/writes which could lead to any number of weird and near impossible to diagnose issues. Instead, you should be using Swing Timer instead, which will ensure that any updates you make are made within the context of the Event Dispatching Thread. You should also be using a single Timer and scheduling everything in a simple update pass - this will generally improve performance

Java-GUI Key Pressed Not Functioning Correctly

So I looked at tons of different threads about this but all of the suggestions of how to make it work; I have done, so it should work. I have gotten it to work before, and I am doing the same thing as when I had images move in another program of mine. Anyways, this is a space shooter like game. I am working on the class in charge of the player vs player. You will see the comment for spacebar and key 'e' will have a shooting in added for later. Shooting is another class, that way I can rapid fire and can control each bullet because there independent objects. Anyways, I did some test with printing out stuff, and I know the timer works. I know the move method is working, because I see my images move on screen. However, I have no control. I then put a print statement in the key pressed area, and it is not printing anything. So I know that is the code that is somehow wrong. So any help would be great as I am stumped. This is not for a class in college or high school. It is a personal project. Here is the code:
import javax.swing.*;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class PlayervsPlayer implements KeyListener,ActionListener{
private JFrame window;
private Timer timer;
private int win_size;
private int ship_clearence=45;
private int speed=3;
private final int stop1=0;
private final int stop2=1;
private final int left1=2;
private final int left2=3;
private final int right1=4;
private final int right2=5;
private int dir1=left1;
private int dir2=right2;
Sprite background;
Sprite ship1=new Sprite("Spaceship.png");
Sprite ship2=new Sprite("Spaceship2.png");
public PlayervsPlayer(JFrame w,Sprite backdrop,int win_s) {
window=w;
background=backdrop;
win_size=win_s;
window.addKeyListener(this);
}
public void pvpmain() {
System.out.println("Player vs Player working!");
ship1.setSize(125,125);
ship1.setLocation((int)((win_size/2)-(ship1.getWidth()/2)),win_size-ship1.getHeight()-ship_clearence);
ship2.setSize(125,125);
ship2.setLocation((int)((win_size/2)-(ship1.getWidth()/2)),0);
window.add(ship1,0);
window.add(ship2,0);
window.repaint();
timer = new Timer( 10, this );
timer.start();
}
public void keyPressed(KeyEvent e) {
int key=e.getKeyCode();
if ( key == KeyEvent.VK_RIGHT ){
System.out.println("Right Key");//
dir1 = right1;
}
else if (key==KeyEvent.VK_LEFT) {
dir1=left1;
}
else if (key==KeyEvent.VK_SPACE) {
//Nothing for now as for shooting
}
if (key==KeyEvent.VK_Q) {
dir2=left2;
}
else if (key==KeyEvent.VK_W) {
dir2=right2;
}
else if (key==KeyEvent.VK_E) {
//Nothing for now as for shooting
}
}
public void move() {
if (dir1==left1) {
if (ship1.getX()<=speed) {
dir1=stop1;
}
else {
ship1.setLocation(ship1.getX()-speed,ship1.getY());
}
}
else if (dir1==right1) {
if (ship1.getX()+ship1.getWidth()>=win_size-speed) {
dir1=stop1;
}
else {
ship1.setLocation(ship1.getX()+speed,ship1.getY());
}
}
if (dir2==left2) {
if (ship2.getX()<=speed) {
dir2=stop2;
}
else {
ship2.setLocation(ship2.getX()-speed,ship2.getY());
}
}
else if (dir2==right2) {
if (ship2.getX()+ship2.getWidth()>=win_size-speed) {
dir2=stop2;
}
else {
ship2.setLocation(ship2.getX()+speed,ship2.getY());
}
}
}
public void actionPerformed(ActionEvent e) {
if ( e.getSource() == timer ){
System.out.println("Timer Working!");
move();
}
}
public void keyTyped(KeyEvent e) {
//Nothing
}
public void keyReleased(KeyEvent e) {
//Nothing
}
}
Thanks in advance.
Your primary issue is related to the fact that KeyListener is unreliable in the application you are trying to use it. KeyListener requires that the component it is registered to is capable of receiving keyboard focus AND has keyboard focus before it will trigger key events. It's very easy for focus to be stolen by other components.
The most reliable solution to your problem is to make use of the key bindings API, which was in part, developed to solve this very issue.
You may also want to have a read of How to Use Actions to understand how this part of the API works
So, adapting the code from Trying to move JLabels on a JPanel with GridLayout, which is the simplest example which is most closely aligned with what you seem to be trying to do, you could end up with something like...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel player;
public TestPane() {
player = makeLabel("P");
player.setSize(player.getPreferredSize());
add(player);
addKeyBinding("left", KeyEvent.VK_LEFT, new MoveAction(player, -4, 0));
addKeyBinding("right", KeyEvent.VK_RIGHT, new MoveAction(player, 4, 0));
addKeyBinding("up", KeyEvent.VK_UP, new MoveAction(player, 0, -4));
addKeyBinding("down", KeyEvent.VK_DOWN, new MoveAction(player, 0, 4));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void addKeyBinding(String name, int keyCode, Action action) {
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(KeyStroke.getKeyStroke(keyCode, 0), name);
actionMap.put(name, action);
}
protected JLabel makeLabel(String text) {
JLabel label = new JLabel(text);
label.setBorder(new CompoundBorder(
new LineBorder(Color.GRAY),
new EmptyBorder(4, 4, 4, 4)));
return label;
}
public class MoveAction extends AbstractAction {
private final int xDelta, yDelta;
private final JComponent component;
public MoveAction(JComponent component, int xDelta, int yDelta) {
this.component = component;
this.xDelta = xDelta;
this.yDelta = yDelta;
}
#Override
public void actionPerformed(ActionEvent e) {
Point location = component.getLocation();
location.x += xDelta;
location.y += yDelta;
component.setLocation(location);
repaint();
}
}
}
}
But what about multiple, simultaneous, key stokes?
Well, this isn't a unique problem, which is most commonly solved by using a series of flags which determine if a key is currently been pressed or not. You then use these flags to make determinations about how best to move the object
So, adapting from the first example, you might end up with something like...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
public class Test2 {
public static void main(String[] args) {
new Test2();
}
public Test2() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public enum Direction {
UP, DOWN, LEFT, RIGHT;
}
public class Controller {
private Set<Direction> directions;
private JComponent player;
public Controller(JComponent player) {
this.player = player;
directions = new TreeSet<>();
}
public void released(Direction direction) {
directions.remove(direction);
updatePosition();
}
public void pressed(Direction direction) {
directions.add(direction);
updatePosition();
}
protected void updatePosition() {
Point location = player.getLocation();
if (directions.contains(Direction.UP)) {
location.y -= 4;
}
if (directions.contains(Direction.DOWN)) {
location.y += 4;
}
if (directions.contains(Direction.LEFT)) {
location.x -= 4;
}
if (directions.contains(Direction.RIGHT)) {
location.x += 4;
}
player.setLocation(location);
}
}
public class TestPane extends JPanel {
private JLabel player;
public TestPane() {
player = makeLabel("P");
player.setSize(player.getPreferredSize());
add(player);
Controller controller = new Controller(player);
addKeyBinding("left", KeyEvent.VK_LEFT, Direction.LEFT, controller);
addKeyBinding("right", KeyEvent.VK_RIGHT, Direction.RIGHT, controller);
addKeyBinding("up", KeyEvent.VK_UP, Direction.UP, controller);
addKeyBinding("down", KeyEvent.VK_DOWN, Direction.DOWN, controller);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void addKeyBinding(String name, int keyCode, Direction direction, Controller controller) {
InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(KeyStroke.getKeyStroke(keyCode, 0, true), name + "-released");
inputMap.put(KeyStroke.getKeyStroke(keyCode, 0, false), name + "-pressed");
actionMap.put(name + "-released", new MoveAction(direction, controller, true));
actionMap.put(name + "-pressed", new MoveAction(direction, controller, false));
}
protected JLabel makeLabel(String text) {
JLabel label = new JLabel(text);
label.setBorder(new CompoundBorder(
new LineBorder(Color.GRAY),
new EmptyBorder(4, 4, 4, 4)));
return label;
}
public class MoveAction extends AbstractAction {
private Direction direction;
private Controller controller;
private boolean released;
public MoveAction(Direction direction, Controller controller, boolean released) {
this.direction = direction;
this.controller = controller;
this.released = released;
}
#Override
public void actionPerformed(ActionEvent e) {
if (released) {
controller.released(direction);
} else {
controller.pressed(direction);
}
}
}
}
}
Next time, try to work with some ones code instead of forcing them to restructure and make a suggestion to use this key binding thing. If you think key binding is so great, why don't you modify my code with key binding instead, lets see how complicated it is then
Sigh - Because I shouldn't have to, even in your own words, you didn't want a "copy and paste" answer, but, apparent that is what you want ...
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.beans.PropertyChangeListener;
// I'd prefer to extend from JPanel, as it provides bases for
// self contained responsibility, but apparently, that's too "advanced"
public class PlayervsPlayer implements ActionListener {
private JFrame window;
private Timer timer;
private int win_size;
private int ship_clearence = 45;
private int speed = 3;
private final int stop1 = 0;
private final int stop2 = 1;
private final int left1 = 2;
private final int left2 = 3;
private final int right1 = 4;
private final int right2 = 5;
private int dir1 = left1;
private int dir2 = right2;
// Sprite background;
JLabel ship1 = new JLabel("Spaceship.png");
JLabel ship2 = new JLabel("Spaceship2.png");
public PlayervsPlayer(JFrame w, int win_s) {
window = w;
// background = backdrop;
win_size = win_s;
JComponent contenPane = (JComponent) w.getContentPane();
InputMap inputMap = contenPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = contenPane.getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "player1-left");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "player1-right");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "player2-left");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_E, 0), "player2-right");
// I'd prefer a single "Move Action" class which could
// make these updates, but that might be "too advanced"
actionMap.put("player1-left", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Player 1 - left");
dir1 = left1;
}
});
actionMap.put("player1-right", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Player 1 - right");
dir1 = right1;
}
});
actionMap.put("player2-left", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Player 2 - left");
dir2 = left2;
}
});
actionMap.put("player2-right", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Player 2 - right");
dir2 = right2;
}
});
}
public void pvpmain() {
System.out.println("Player vs Player working!");
ship1.setSize(125, 125);
ship1.setLocation((int) ((win_size / 2) - (ship1.getWidth() / 2)), win_size - ship1.getHeight() - ship_clearence);
ship2.setSize(125, 125);
ship2.setLocation((int) ((win_size / 2) - (ship1.getWidth() / 2)), 0);
window.add(ship1, 0);
window.add(ship2, 0);
window.repaint();
timer = new Timer(10, this);
timer.start();
}
public void move() {
if (dir1 == left1) {
if (ship1.getX() <= speed) {
dir1 = stop1;
} else {
ship1.setLocation(ship1.getX() - speed, ship1.getY());
}
} else if (dir1 == right1) {
if (ship1.getX() + ship1.getWidth() >= win_size - speed) {
dir1 = stop1;
} else {
ship1.setLocation(ship1.getX() + speed, ship1.getY());
}
}
if (dir2 == left2) {
if (ship2.getX() <= speed) {
dir2 = stop2;
} else {
ship2.setLocation(ship2.getX() - speed, ship2.getY());
}
} else if (dir2 == right2) {
if (ship2.getX() + ship2.getWidth() >= win_size - speed) {
dir2 = stop2;
} else {
ship2.setLocation(ship2.getX() + speed, ship2.getY());
}
}
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == timer) {
System.out.println("Timer Working!");
move();
}
}
}
But the players won't stop moving when you release a key...
Hmm, yes, that is true, but the original code didn't seem to have that functionality either
So, in the PlayervsPlayer constructor, we'd replace the existing bindings with something more like...
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "player1-left-pressed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "player1-right-pressed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "player2-left-pressed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_E, 0, false), "player2-right-pressed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "player1-left-released");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "player1-right-released");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "player2-left-released");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_E, 0, true), "player2-right-released");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "space");
// I'd prefer this to be a self containted unit of work, but for demonstration purposes
actionMap.put("player1-left-pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Player 1 - left");
dir1 = left1;
}
});
actionMap.put("player1-right-pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Player 1 - right");
dir1 = right1;
}
});
actionMap.put("player2-left-pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Player 2 - left");
dir2 = left2;
}
});
actionMap.put("player2-right-pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Player 2 - right");
dir2 = right2;
}
});
actionMap.put("player1-left-released", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Player 1 - left");
dir1 = stop1;
}
});
actionMap.put("player1-right-released", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Player 1 - stop");
dir1 = stop1;
}
});
actionMap.put("player2-left-released", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Player 2 - stop");
dir2 = stop2;
}
});
actionMap.put("player2-right-released", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Player 2 - stop");
dir2 = stop2;
}
});
actionMap.put("space", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Pew pew pew");
}
});
I also added Space because I forget to put it in the previous example
I would be interested in seeing how much longer key binding is to my code
My favourite topic - reduce and reuse. As I stated in my comments above, I'd prefer to have a single "move action" class which could change some kind of state, here I've used a Set, but you could pass an instance of PlayervsPlayer and have the MoveAction call a method on it, telling the class what action has occurred, I prefer this method as it decouples the code (makes it more re-usable)
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Set;
import java.util.TreeSet;
// I'd prefer to extend from JPanel, as it provides bases for
// self contained responsibility, but apparently, that's too "advanced"
public class PlayervsPlayer implements ActionListener {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLayout(null);
new PlayervsPlayer(frame, 400).pvpmain();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private JFrame window;
private Timer timer;
private int win_size;
private int ship_clearence = 45;
private int speed = 3;
private final int stop1 = 0;
private final int stop2 = 1;
private final int left1 = 2;
private final int left2 = 3;
private final int right1 = 4;
private final int right2 = 5;
// private int dir1 = left1;
// private int dir2 = right2;
// Sprite background;
JLabel ship1 = new JLabel("Spaceship.png");
JLabel ship2 = new JLabel("Spaceship2.png");
private Set<Integer> playerKeys;
public PlayervsPlayer(JFrame w, int win_s) {
window = w;
// background = backdrop;
win_size = win_s;
playerKeys = new TreeSet<>();
playerKeys = new TreeSet<>();
playerKeys.add(left1);
playerKeys.add(right2);
JComponent contenPane = (JComponent) w.getContentPane();
InputMap inputMap = contenPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = contenPane.getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "player1-left");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "player1-right");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "player2-left");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_E, 0), "player2-right");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "player1-left-pressed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "player1-right-pressed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "player2-left-pressed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_E, 0, false), "player2-right-pressed");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "player1-left-released");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "player1-right-released");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "player2-left-released");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_E, 0, true), "player2-right-released");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "space");
// I'd prefer this to be a self containted unit of work, but for demonstration purposes
actionMap.put("player1-left-pressed", new MoveAction(playerKeys, left1, false));
actionMap.put("player1-right-pressed", new MoveAction(playerKeys, right1, false));
actionMap.put("player2-left-pressed", new MoveAction(playerKeys, left2, false));
actionMap.put("player2-right-pressed", new MoveAction(playerKeys, right2, false));
actionMap.put("player1-left-released", new MoveAction(playerKeys, left1, true));
actionMap.put("player1-right-released", new MoveAction(playerKeys, right1, true));
actionMap.put("player2-left-released", new MoveAction(playerKeys, left2, true));
actionMap.put("player2-right-released", new MoveAction(playerKeys, right2, true));
actionMap.put("space", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Pew pew pew");
}
});
}
public void pvpmain() {
System.out.println("Player vs Player working!");
ship1.setSize(125, 125);
ship1.setLocation((int) ((win_size / 2) - (ship1.getWidth() / 2)), win_size - ship1.getHeight() - ship_clearence);
ship2.setSize(125, 125);
ship2.setLocation((int) ((win_size / 2) - (ship1.getWidth() / 2)), 0);
window.add(ship1, 0);
window.add(ship2, 0);
window.repaint();
timer = new Timer(10, this);
timer.start();
}
public void move() {
if (playerKeys.contains(left1)) {
if (ship1.getX() <= speed) {
playerKeys.clear();
} else {
ship1.setLocation(ship1.getX() - speed, ship1.getY());
}
} else if (playerKeys.contains(right1)) {
if (ship1.getX() + ship1.getWidth() >= win_size - speed) {
playerKeys.clear();
} else {
ship1.setLocation(ship1.getX() + speed, ship1.getY());
}
}
if (playerKeys.contains(left2)) {
if (ship2.getX() <= speed) {
playerKeys.clear();
} else {
ship2.setLocation(ship2.getX() - speed, ship2.getY());
}
} else if (playerKeys.contains(right2)) {
if (ship2.getX() + ship2.getWidth() >= win_size - speed) {
playerKeys.clear();
} else {
ship2.setLocation(ship2.getX() + speed, ship2.getY());
}
}
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == timer) {
move();
}
}
public class MoveAction extends AbstractAction {
private Set<Integer> keys;
private Integer action;
private boolean released;
public MoveAction(Set<Integer> keys, Integer action, boolean released) {
this.keys = keys;
this.action = action;
this.released = released;
}
#Override
public void actionPerformed(ActionEvent e) {
if (released) {
keys.remove(action);
} else {
keys.add(action);
}
}
}
}

How do I move an object using Keyboard Control? [duplicate]

I have written a sample code using KeyListener in Java,
I have created a JPanel, then set its focusable to true, I have created a KeyListener, requested a focus and then added the KeyListener to my panel. But the methods for the keyListener are never called. It seems although I have requested focus, it does not focus.
Can anyone help?
listener = new KeyLis();
this.setFocusable(true);
this.requestFocus();
this.addKeyListener(listener);
class KeyLis implements KeyListener{
#Override
public void keyPressed(KeyEvent e) {
currentver += 5;
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT : if(horizontalyInBounds()) currentPos-= 5;
break;
case KeyEvent.VK_RIGHT: if(horizontalyInBounds()) currentPos+= 5;
break;
}
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
}
}
If any runnable code should be needed:
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class test extends JFrame {
private AreaOfGame areaOfGame;
public test()
{
super("");
setVisible(true);
this.setBackground(Color.darkGray);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
setLayout(null);
setBounds(200, 10, 400, 700);
areaOfGame = new AreaOfGame();
this.add(areaOfGame);
startGame();
}
public int generateNext()
{
Random r = new Random();
int n = r.nextInt(7);
return n;
}
public void startGame()
{
while(!areaOfGame.GameOver())
{
areaOfGame.startGame(generateNext());
}
}
public static void main(String[] args) {
new MainFrame();
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JPanel;
public class AreaOfGame extends JPanel {
private static final int rightside = 370;
private int bottom;
private int top;
private int currentPos;
private int currentver;
private KeyLis listener;
public AreaOfGame()
{
super();
bottom = 650;
top = 50;
setLayout(null);
setBounds(20, 50, 350, 600);
setVisible(true);
this.setBackground(Color.lightGray);
listener = new KeyLis();
this.setFocusable(true);
if(this.requestFocus(true))
System.out.println("true");;
this.addKeyListener(listener);
currentPos = 150;
currentver=0;
}
public void startGame(int n)
{
while(verticallyInBound()){
System.out.println("anything");
}
}
public boolean verticallyInBound()
{
if(currentPos<= bottom -50)
return true;
return false;
}
public boolean GameOver()
{
if(top>= bottom){
System.out.println("game over");
return true;
}
else return false;
}
public boolean horizontalyInBounds()
{
if(currentPos<=rightside && currentPos>= 20)
return true;
else return false;
}
class KeyLis implements KeyListener{
#Override
public void keyPressed(KeyEvent e) {
System.out.println("called");
currentver += 5;
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT : if(horizontalyInBounds()) currentPos-= 5; break;
case KeyEvent.VK_RIGHT: if(horizontalyInBounds()) currentPos+= 5; break;
}
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
System.out.println("called 3");
}
}
}
I'll bet that you're requesting focus before the JPanel has been rendered (before the top level window has either had pack() or setVisible(true) called), and if so, this won't work. Focus request will only be possibly granted after components have been rendered. Have you checked what your call to requestFocus() has returned? It must return true for your call to have any chance for a success. Also it's better to use requestFocusInWindow() rather than requestFocus().
But more importantly, you shouldn't be using KeyListeners for this but rather key bindings, a higher level concept that Swing itself uses to respond to key presses.
Edit
An example of an SSCCE:
import java.awt.Dimension;
import java.awt.event.*;
import javax.swing.*;
public class TestKeyListener extends JPanel {
private KeyLis listener;
public TestKeyListener() {
add(new JButton("Foo")); // something to draw off focus
listener = new KeyLis();
this.setFocusable(true);
this.requestFocus();
this.addKeyListener(listener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
private class KeyLis extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
System.out.println("VK_LEFT pressed");
break;
case KeyEvent.VK_RIGHT:
System.out.println("VK_RIGHT pressed");
break;
}
}
}
private static void createAndShowGui() {
TestKeyListener mainPanel = new TestKeyListener();
JFrame frame = new JFrame("TestKeyListener");
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();
}
});
}
}
Edit 2
And the equivalent SSCCE using Key Bindings:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class TestKeyBindings extends JPanel {
public TestKeyBindings() {
add(new JButton("Foo")); // something to draw off focus
setKeyBindings();
}
private void setKeyBindings() {
ActionMap actionMap = getActionMap();
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition );
String vkLeft = "VK_LEFT";
String vkRight = "VK_RIGHT";
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), vkLeft);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), vkRight);
actionMap.put(vkLeft, new KeyAction(vkLeft));
actionMap.put(vkRight, new KeyAction(vkRight));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
private class KeyAction extends AbstractAction {
public KeyAction(String actionCommand) {
putValue(ACTION_COMMAND_KEY, actionCommand);
}
#Override
public void actionPerformed(ActionEvent actionEvt) {
System.out.println(actionEvt.getActionCommand() + " pressed");
}
}
private static void createAndShowGui() {
TestKeyBindings mainPanel = new TestKeyBindings();
JFrame frame = new JFrame("TestKeyListener");
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();
}
});
}
}
Edit 3
Regarding your recent SSCCE, your while (true) loops are blocking your Swing event thread and may prevent user interaction or painting from happening. Better to use a Swing Timer rather than while (true). For example:
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class BbbTest extends JFrame {
private AreaOfGame areaOfGame;
public BbbTest() {
super("");
// setVisible(true);
this.setBackground(Color.darkGray);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
setLayout(null);
setBounds(200, 10, 400, 700);
areaOfGame = new AreaOfGame();
this.add(areaOfGame);
setVisible(true);
startGame();
}
public int generateNext() {
Random r = new Random();
int n = r.nextInt(7);
return n;
}
public void startGame() {
// while (!areaOfGame.GameOver()) {
// areaOfGame.startGame(generateNext());
// }
areaOfGame.startGame(generateNext());
}
public static void main(String[] args) {
new BbbTest();
}
class AreaOfGame extends JPanel {
private static final int rightside = 370;
private int bottom;
private int top;
private int currentPos;
private int currentver;
private KeyLis listener;
public AreaOfGame() {
super();
bottom = 650;
top = 50;
setLayout(null);
setBounds(20, 50, 350, 600);
setVisible(true);
this.setBackground(Color.lightGray);
listener = new KeyLis();
this.setFocusable(true);
if (this.requestFocus(true))
System.out.println("true");
;
this.addKeyListener(listener);
currentPos = 150;
currentver = 0;
}
public void startGame(int n) {
// while (verticallyInBound()) {
// System.out.println("anything");
// }
int timeDelay = 50; // msecs delay
new Timer(timeDelay , new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
System.out.println("anything");
}
}).start();
}
public boolean verticallyInBound() {
if (currentPos <= bottom - 50)
return true;
return false;
}
public boolean GameOver() {
if (top >= bottom) {
System.out.println("game over");
return true;
}
else
return false;
}
public boolean horizontalyInBounds() {
if (currentPos <= rightside && currentPos >= 20)
return true;
else
return false;
}
class KeyLis implements KeyListener {
#Override
public void keyPressed(KeyEvent e) {
System.out.println("called");
currentver += 5;
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
if (horizontalyInBounds())
currentPos -= 5;
break;
case KeyEvent.VK_RIGHT:
if (horizontalyInBounds())
currentPos += 5;
break;
}
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
System.out.println("called 3");
}
}
}
}
It's possible to use the "TAB" button to switch between the buttons and the key listener.
I have a program with one button that after I press it, the key listener does not work.
I realized that if you press the "TAB" button, the "Attention" or "focus" of the program returns to the key listener.
maybe this will help: http://docstore.mik.ua/orelly/java-ent/jfc/ch03_08.htm

Java object movement

I am trying to get a circle to move through the input of a keyboard. I am not able to move the object at all. Can someone help me figure out what is wrong? Here is my code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
public class AlienInvader extends JPanel implements KeyListener{
Constants constant = new Constants();
public void update() {
constant.x += constant.xvel;
addKeyListener(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.MAGENTA);
g.fillOval(constant.x, constant.y, 30, 30);
repaint();
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println(constant.x);
switch(e.getKeyCode()) {
case KeyEvent.VK_LEFT:
constant.xvel = -1;
break;
case KeyEvent.VK_RIGHT:
constant.xvel = 1;
break;
}
}
#Override
public void keyReleased(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_LEFT:
constant.xvel = -1;
break;
case KeyEvent.VK_RIGHT:
constant.xvel = 1;
break;
}
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
I am not sure what I am doing wrong. I thought it was because I wasn't calling the update method, but when I added a if statement in paintComponent (so it only calls itself once) and tried it, I had no luck.
To start with, don't call repaint within any paintXxx method. Paint methods are typically called in response to a call to repaint, therefore you are creating a nasty, never ending, ever consuming loop of resource hell.
Secondly, KeyListeners only respond to key events when 1- The component the are registered to are focusable 2- When the component they are registered to have focus.
They are a poor choice in this case. Use Key bindings instead
Thirdly, you are not providing a preferredSize hint for layout managers to use. This may or may not be a bad thing in your case, but it's possible that you component will be laid out with a size of 0x0
Example
Something like....
import java.awt.BorderLayout;
import java.awt.Color;
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 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 MoveCircle {
public static void main(String[] args) {
new MoveCircle();
}
public MoveCircle() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private int xDelta = 0;
private int keyPressCount = 0;
private Timer repaintTimer;
private int xPos = 0;
private int radius = 10;
public TestPane() {
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "pressed.left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "pressed.right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "released.left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "released.right");
am.put("pressed.left", new MoveAction(-2, true));
am.put("pressed.right", new MoveAction(2, true));
am.put("released.left", new MoveAction(0, false));
am.put("released.right", new MoveAction(0, false));
repaintTimer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
xPos += xDelta;
if (xPos < 0) {
xPos = 0;
} else if (xPos + radius > getWidth()) {
xPos = getWidth() - radius;
}
repaint();
}
});
repaintTimer.setInitialDelay(0);
repaintTimer.setRepeats(true);
repaintTimer.setCoalesce(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.drawOval(xPos, 0, radius, radius);
g2d.dispose();
}
public class MoveAction extends AbstractAction {
private int direction;
private boolean keyDown;
public MoveAction(int direction, boolean down) {
this.direction = direction;
keyDown = down;
}
#Override
public void actionPerformed(ActionEvent e) {
xDelta = direction;
if (keyDown) {
if (!repaintTimer.isRunning()) {
repaintTimer.start();
}
} else {
repaintTimer.stop();
}
}
}
}
}
For example...

Categories

Resources