So i have created an extended version of JPanel and unfortunately it doesn't respond to any key typing. Could you tell me what the problem is? I searched all the others posts but i couldn't find my error.
public class MyPanel extends JPanel implements ActionListener,KeyListener{
Timer tm=new Timer(5,this);
int x=0,y=0 ,velX=0, velY=0;
public MyPanel(){
tm.start();
addKeyListener(this);
setFocusable(true);
requestFocusInWindow();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.fillRect(0,0,this.getWidth(),this.getHeight());
g.setColor(Color.RED);
g.fillRect(x,30,50,30);
}
public void actionPerformed(ActionEvent e){
if(x<0||x>370)
velX=-velX;
if(y<0||y>370)
velY=-velY;
y=y+velY;
x=x+velX;
repaint();
}
public void keyPressed(KeyEvent e){
int c=e.getKeyCode();
System.out.println("Cascsadas");
if(c==KeyEvent.VK_LEFT){
velX=-1;
velY=0;
}
if(c==KeyEvent.VK_UP){
velX=0;
velY=-1;
}
if(c==KeyEvent.VK_RIGHT){
velX=1;
velY=0;
}
if(c==KeyEvent.VK_DOWN){
velX=0;
velY=1;
}
}
public void keyTyped(KeyEvent e){};
public void keyReleased(KeyEvent e){};
}
And the class where i am using this JPanel is:
public class Tester
{
public static void main(String[] args){
MyPanel t=new MyPanel();
JFrame jf=new JFrame();
jf.setTitle("Tutorial");
jf.setVisible(true);
jf.setSize(600,400);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.getContentPane().add(t,BorderLayout.CENTER);
}
}
Your code doesn't work because your panel doesn't have focus.
The requestFocusInWindow() method only works when the panel is displayed on GUI is visible. Invoking the method in the constructor has no effect (and is not needed).
However, the real problem is that you add the panel to the frame AFTER the frame is visible. Your code should be something like:
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.getContentPane().add(t,BorderLayout.CENTER);
jf.setSize(600,400);
jf.setVisible(true);
The key is adding the panel to the content pane before the frame is made visible. It also doesn't make sense to make the frame visible and then change its size, so I always make the frame visiable as the last statement.
I searched all the others posts but i couldn't find my error
I find that hard to believe. This question is asked daily and we always recommend to use Key Bindings, so why are you still trying to use a KeyListener?
Swing was designed to be used with Key Bindings. See Motion Using the Keyboard for more information and an approach that does use Key Bindings.
I have posted an answer in the same context here
Diagonal movement of a simple sprite (up-down-left-right movement already done).
This post about KeyListener will help you to understand it more.
Here is the sample code to start:
(moving in all the direction left,right,top,bottom and diagonally also)
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.Set;
import java.util.TreeSet;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Apple extends JPanel implements ActionListener, KeyListener {
Timer timer = new Timer(5, this); // this refers to actionListener
int x = 0, velx = 0;
int y = 0, vely = 0;
public Apple() {
timer.start();
addKeyListener(this); // this refers to keylistener
setFocusable(true);
setFocusTraversalKeysEnabled(false); // because we are not using the shift or ctrl key
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// outer rectangle
g.setColor(Color.BLUE);
g.fillRect(x, y, 50, 50);
}
public static void main(String[] args) {
Apple apple = new Apple();
apple.setSize(500, 500);
JFrame frame = new JFrame();
frame.add(apple);
frame.setLayout(null);
frame.setTitle("The Game");
frame.setSize(500, 500);
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
// animates rectangle
public void actionPerformed(ActionEvent arg0) {
if (x < 0) {
velx = 0;
x = 0;
}
if (x > 450) {
velx = 0;
x = 450;
}
if (y < 0) {
vely = 0;
y = 0;
}
if (y > 450) {
vely = 0;
y = 450;
}
x = x + velx;
y = y + vely;
repaint();
}
// Set of currently pressed keys
private final Set<Integer> pressed = new TreeSet<Integer>();
#Override
public void keyPressed(KeyEvent arg0) {
System.out.println(KeyEvent.VK_LEFT + "-" + KeyEvent.VK_RIGHT + "-" + KeyEvent.VK_UP + "-"
+ KeyEvent.VK_DOWN);
int c = arg0.getKeyCode();
pressed.add(c);
if (pressed.size() > 1) {
Integer[] array = pressed.toArray(new Integer[] {});
if (array[0] == KeyEvent.VK_LEFT && array[1] == KeyEvent.VK_UP) {
velx = -4;
vely = -4;
} else if (array[0] == KeyEvent.VK_UP && array[1] == KeyEvent.VK_RIGHT) {
velx = 4;
vely = 4;
} else if (array[0] == KeyEvent.VK_RIGHT && array[1] == KeyEvent.VK_DOWN) {
velx = 4;
vely = -4;
} else if (array[0] == KeyEvent.VK_LEFT && array[1] == KeyEvent.VK_DOWN) {
velx = -4;
vely = 4;
}
} else {
if (c == KeyEvent.VK_LEFT) {
velx = -4;
vely = 0;
} else if (c == KeyEvent.VK_RIGHT) {
velx = 4;
vely = 0;
} else if (c == KeyEvent.VK_UP) {
velx = 0;
vely = -4;
} else if (c == KeyEvent.VK_DOWN) {
velx = 0;
vely = 4;
}
}
}
#Override
public void keyReleased(KeyEvent arg0) {
velx = 0;
vely = 0;
pressed.remove(Integer.valueOf(arg0.getKeyCode()));
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
Related
I am trying to move a rectangle while the key is pressed and to stop it on release like the game "Snake". As reference I followed this tutorial.
I tried to adjust a few things in my code:
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
public class f3 extends JPanel implements ActionListener, KeyListener {
static JFrame frame;
static Timer t;
static int x, y, velx, vely, c;
f3(){
t = new Timer(5, this);
x = 0;
y = 0;
velx = 0;
vely = 0;
frame = new JFrame();
frame.addKeyListener(this);
frame.setFocusable(true);
frame.setFocusTraversalKeysEnabled(false);
frame.setSize(500,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(x, y, 50, 30);
t.start();
}
public void actionPerformed(ActionEvent e) {
x = x + velx;
y = y + vely;
repaint();
}
public void keyPressed(KeyEvent e) {
c = e.getKeyCode();
if(c == KeyEvent.VK_RIGHT) {
velx = 1;
vely = 0;
}
if(c == KeyEvent.VK_LEFT) {
velx = -1;
vely = 0;
}
if(c == KeyEvent.VK_UP) {
velx = 0;
vely = -1;
}
if(c == KeyEvent.VK_DOWN) {
velx = 0;
vely = 1;
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
public static void main(String args[]) {
new f3();
}
}
The value of velx and vely are set after a key event is triggered. Since you are using a Timer here, the GUI will continuously update because actionPerformed is repeatedly triggered.
Remove the Timer, then put the change section of keyPressed to this form and you will get a desired result.
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_RIGHT){
velx = 1;
vely = 0;
x = x + velx;
y = y + vely;
repaint();
}
}
Since velx and vely indicate the velocity of the movement (as opposed to moving the player one space at a time, for instance), you will want to also ensure keyReleased returns the appropriate velocity to 0 when the specific key associated with that axis is released.
You do not have a handler for keyReleased method, where you should set velocities to zero as such:
public void keyReleased(KeyEvent e) {
velx = 0;
vely = 0;
}
I am trying to make a rectangle move with arrow keys (for a game) but I am getting an error message. It says this, but it still doesnt work when I change it. I have tried multiple times but still receive the same error. Does anyone know why this error is appearing?
this is the error:
java.lang.Error: Do not use javax.swing.JFrame.add() use javax.swing.JFrame.getContentPane().add() instead
at javax.swing.JFrame.createRootPaneException(Unknown Source)
at javax.swing.JFrame.addImpl(Unknown Source)
at java.awt.Container.add(Unknown Source)
at Tutorial.main(Tutorial.java:109)
Here is my code:
// The "Test" class.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Tutorial extends JPanel implements ActionListener, KeyListener
{
Timer tm = new Timer (5,this);
int x = 0, y = 0, velX = 0, velY = 0;
public Tutorial ()
{
tm.start();
addKeyListener(this);
setFocusable (true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent (Graphics g)
{
super.paintComponent (g);
g.setColor (Color.RED);
g.fillRect (x, y, 50, 30);
}
public void actionPerformed (ActionEvent e)
{
if (x < 0)
{
velX = 0;
x = 0;
}
else if (x > 530)
{
velX = 0;
x = 530;
}
if (y < 0)
{
velY = 0;
y = 0;
}
else if (y > 330)
{
velY = 0;
y = 330;
}
x = x + velX;
y = y + velY;
repaint ();
}
public void keyPressed (KeyEvent e)
{
int c = e.getKeyCode ();
if (c == KeyEvent.VK_LEFT)
{
velX = -1;
velY = 0;
}
if (c == KeyEvent.VK_UP)
{
velX = 0;
velY = -1;
}
if (c == KeyEvent.VK_RIGHT)
{
velX = 1;
velY = 0;
}
if (c == KeyEvent.VK_DOWN)
{
velX = 0;
velY = 1;
}
}
public void keyTyped (KeyEvent e) {}
public void keyReleased (KeyEvent e)
{
velX = 0;
velY = 0;
}
public static void main (String arge [])
{
Tutorial t = new Tutorial ();
JFrame jf = new JFrame ();
jf.setTitle ("Tutorial");
jf.setSize (600, 400);
jf.setVisible (true);
jf.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
jf.add(t);
}
} // Test class
I am making a little program where two rectangles drive around a race car track. When I run the program everything goes as planned and I can move the black rectangle around the track using the arrow keys. If I want to move the red rectangle using W,A,S,D, what should I do?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class first extends JLabel implements ActionListener, KeyListener {
Timer t = new Timer(5, this);
double x = 0, y = 25, velx = 0, vely = 0;
public first() {
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public static void main(String[] args) {
JLabel jl = new JLabel();
JPanel jp = new JPanel();
JFrame f = new JFrame();
first m = new first();
f.add(m);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(1650,1080);
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
//The image below is a race car track I drew in Microsoft Paint
jl.setIcon(new ImageIcon("C:\\Users\\Jack\\Pictures\\JavaImages\\racetrack2.png"));
f.add(jp);
jp.add(jl);
f.validate();
}
public void paintComponent (Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
g2.fill(new Rectangle2D.Double(0, 80, 90, 50));
g2.setColor(Color.BLACK);
g2.fill(new Rectangle2D.Double(x, y, 90, 50));
}
public void actionPerformed(ActionEvent e) {
repaint();
x += velx;
y += vely;
}
public void up() {
vely = -3.5;
velx = 0;
}
public void down() {
vely = 3.5;
velx = 0;
}
public void left() {
velx = -4.5;
vely = 0;
}
public void right() {
velx = 4.5;
vely = 0;
}
/*public void upStopped() {
velx = 0;
vely = 0;
}
public void downStopped() {
velx = 0;
vely = 0;
}
public void leftStopped() {
velx = 0;
vely = 0;
}
public void rightStopped() {
velx = 0;
vely = 0;
}*/
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if(code == KeyEvent.VK_UP) {
up();
}
if(code == KeyEvent.VK_DOWN) {
down();
}
if(code == KeyEvent.VK_LEFT) {
left();
}
if(code == KeyEvent.VK_RIGHT) {
right();
}
if(code == KeyEvent.VK_W) {
}
if(code == KeyEvent.VK_S) {
}
if(code == KeyEvent.VK_A) {
}
if(code == KeyEvent.VK_D) {
}
}
public void keyReleased(KeyEvent e) {
/*int code2 = e.getKeyCode();
if(code2 == KeyEvent.VK_UP) {
upStopped();
}
if(code2 == KeyEvent.VK_DOWN) {
downStopped();
}
if(code2 == KeyEvent.VK_LEFT) {
leftStopped();
}
if(code2 == KeyEvent.VK_RIGHT) {
rightStopped();
}*/
}
public void keyTyped(KeyEvent e) {}
}
I can move the black rectangle around the track using the arrow keys. If I want to move the red rectangle using W,A,S,D, what should I do?
Use Key Bindings not a KeyListener.
You also need to use a Timer to start the animation when a key is pressed and stop the animation when a key is released, since events can only be generated for a single key at a time.
Check out Motion Using The Keyboard for more information about the above concepts. The keyboardAnimation code is a complete working example implementing both of the concepts.
I should be able to move the rectangle with the arrow keys but after running the program a few times the rectangle does not move. To make the rectangle move I close Netbeans and reopen it. Then the rectangle is able to move but it stops moving after a couple tries. I want to solve this problem so I can make changes.
package project;
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 javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
//KeyListener is use with keyboard
public class main extends JPanel implements ActionListener, KeyListener
{
Timer tm = new Timer(5, this); //for animation
int x = 50, y = 50, velX =0, velY = 0;
public main()
{
tm.start(); //starts timer
addKeyListener(this); //this refearing to KeyListener
setFocusable(true); //enable KeyListener
setFocusTraversalKeysEnabled(false); //shift or tab is not use so F
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(x,y,50,50);
}
public void actionPerformed(ActionEvent e)
{
if (x<0)
{
velX = 0;
x = 0;
}
if (x>500)
{
velX = 0;
x = 500;
}
if (y<0)
{
velY = 0;
y=0;
}
if (y>300)
{
velY = 0;
y = 300;
}
x = x + velX;
y = y + velY;
repaint(); // repaint rectangle
}
public void keyPressed(KeyEvent e)
{
int c = e.getKeyCode(); //get key
if (c == KeyEvent.VK_LEFT) // VK_Left is left arrow
{
velX = -3;
velY = 0;
}
if (c == KeyEvent.VK_UP) // VK_UP is up arrow
{
velX = 0;
velY = -3; // means up
}
if (c == KeyEvent.VK_RIGHT)
{
velX = 3;
velY = 0;
}
if (c == KeyEvent.VK_DOWN)
{
velX = 0;
velY = 3;
}
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e) //when you stop pressing
{
velX = 0;
velY = 0;
}
public static void main(String[] args)
{
main m = new main();
JFrame jf = new JFrame();
jf.setTitle("Tutorial");
jf.setSize(600,400);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(m);
}
}
I have the following code to show you:
public class Test extends JPanel implements ActionListener, KeyListener
{
Timer tm = new Timer(5, this);
int x = 0, y = 0, velX = 0, velY = 0;
public Test()
{
tm.start(); //starts the timer
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paint(Graphics g)
{
super.paint(g);
ImageIcon s = new ImageIcon("C:\\Users\\Owner\\Pictures\\Stick.jpg");
s.paintIcon(this,g,x,y);
}
public void actionPerformed(ActionEvent e)
{
if (x < 0)
{
velX = 0;
x = 0;
}
if (x > 630)
{
velX = 0;
x = 630;
}
if(y < 0)
{
velY = 0;
y = 0;
}
if(y > 430)
{
velY = 0;
y = 430;
}
x = x + velX;
y = y + velY;
repaint();
}
public void keyPressed(KeyEvent e)
{
int c = e.getKeyCode();
if (c == KeyEvent.VK_LEFT)
{
velX = -1;
velY = 0;
}
if(c == KeyEvent.VK_UP)
{
velX = 0;
velY = -1;
}
if(c == KeyEvent.VK_RIGHT)
{
velX = 1;
velY = 0;
}
if(c == KeyEvent.VK_DOWN)
{
velX = 0;
velY = 1;
}
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e)
{
velX = 0;
velY = 0;
}
public static void main(String[] args)
{
Test t = new Test();
JFrame jf = new JFrame();
jf.setTitle("Tutorial");
jf.setSize(700, 600);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(t);
jf.setVisible(true);
}
My problem is I whenever the user holds the right arrow on the keyboard it changes an image, when the user lets go it goes back the the default image. Please tell me how to do that. I think it is a series of if statements in the Graphics class then calling them to the key input but I'm not quite sure. I am also using Eclipse. Thank You.
Override paintComponent instead of paint. See Performing Custom Painting and Painting in AWT and Swing for more details
Use the key bindings API instead of KeyListener, it will cause you less issues. See How to Use Key Bindings for more details
Essentially, you could just have a Image as a class instance field, which was painted by the paintComponent method. When the key was pressed, you would change the image to the "move image" and when it was released, change it back to the "default image"
Updated with example
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.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
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.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 interface Mover {
public enum Direction {
LEFT, RIGHT, NONE;
}
public void setDirection(Direction direction);
public Direction getDirection();
}
public class TestPane extends JPanel implements Mover {
private BufferedImage left;
private BufferedImage right;
private BufferedImage stand;
private BufferedImage current;
private Direction direction = Direction.NONE;
private int xPos;
private int yPos;
public TestPane() {
try {
left = ImageIO.read(getClass().getResource("/Left.png"));
right = ImageIO.read(getClass().getResource("/Right.png"));
stand = ImageIO.read(getClass().getResource("/Stand.png"));
current = stand;
xPos = 100 - (current.getWidth() / 2);
yPos = 100 - (current.getHeight() / 2);
} catch (IOException exp) {
exp.printStackTrace();
}
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "move.left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), new MoveAction(this, Direction.LEFT));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "stop.left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), new MoveAction(this, Direction.NONE));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "move.right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), new MoveAction(this, Direction.RIGHT));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "stop.right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), new MoveAction(this, Direction.NONE));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updatePosition();
repaint();
}
});
timer.start();
}
protected void bindKeyStrokeTo(int condition, String name, KeyStroke keyStroke, Action action) {
InputMap im = getInputMap(condition);
ActionMap am = getActionMap();
im.put(keyStroke, name);
am.put(name, action);
}
#Override
public Direction getDirection() {
return direction;
}
#Override
public void setDirection(Direction direction) {
this.direction = direction;
}
protected void updatePosition() {
switch (getDirection()) {
case LEFT:
current = left;
xPos -= 1;
break;
case RIGHT:
current = right;
xPos += 1;
break;
case NONE:
current = stand;
break;
}
if (xPos < 0) {
xPos = 0;
current = stand;
} else if (xPos + current.getWidth() > getWidth()) {
current = stand;
xPos = getWidth() - current.getWidth();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(current, xPos, yPos, this);
g2d.dispose();
}
}
public class MoveAction extends AbstractAction {
private Mover mover;
private Mover.Direction direction;
public MoveAction(Mover mover, Mover.Direction direction) {
this.mover = mover;
this.direction = direction;
}
#Override
public void actionPerformed(ActionEvent e) {
mover.setDirection(direction);
}
}
}