I encountered a problem when I was coding, When I call repaint anywhere, it doesn't update the image but the program still keeps running:
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.ImageObserver;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class mainMenu extends JPanel implements MouseListener{
Graphics g;
Image playButton = Toolkit.getDefaultToolkit().getImage("game sprites/play_button.png");
private int part = 0;
public static void main(String[] a) {
mainMenu mm = new mainMenu();
mm.makeJFrame();
}
public void makeJFrame(){
JFrame f = new JFrame();
f.setSize(1000, 600);
f.add(new mainMenu());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
f.addMouseListener(this);
f.setTitle("MAIN MENU");
}
public void paintComponent(Graphics g) {
if(part == 0)
System.out.println("0");
g.drawImage( playButton, 330, 200, 294, 102, this);
if(part == 1)
{
System.out.println("1");
g.setColor(Color.RED);
g.fillRect(0, 0, 40, 40);
}
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if(part == 0)
{
if(x > 330 && x < 624 && y > 232 && y < 334)
{
System.out.println("a");
part = 1;
repaint();
}
}
}
public void mouseReleased(MouseEvent e) {}
}
I tested lots of times, and the problem is with the repaint, the program works, but the image stays the same when it shouldn't. It prints out:
0
0
0
a (when I click on the button)
and doesn't print out "a" again even if I click on the button, which it shouldn't since part is set to 1.
Does the image load? This looks suspicious: Image playButton = Toolkit.getDefaultToolkit().getImage("game sprites/play_button.png");. Where are the images stored?
This looks suspicious...
if (part == 0)
System.out.println("0");
g.drawImage(playButton, 330, 200, 294, 102, this);
And is probably meant to be...
if (part == 0) {
System.out.println("0");
g.drawImage(playButton, 330, 200, 294, 102, this);
}
You've broken the paint chain, you MUST call super.paintComponent before you do any custom painting...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
And finally, you have two instances of mainMenu...
The first is the one you have on the screen...
f.add(new MainMenu());
The second is the one that is responding to the mouse events and updating the state of part
f.addMouseListener(this);
Which has nothing to do with the first.
You should avoid making a windows within components (like JPanel) and instead create an instance of MainMenu and add it to an instance of JFrame, for example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MainMenu extends JPanel implements MouseListener {
Image playButton = Toolkit.getDefaultToolkit().getImage("...");
private int part = 0;
public static void main(String[] a) {
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 MainMenu());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public MainMenu() {
addMouseListener(this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println(part);
if (part == 0) {
System.out.println("0");
g.drawImage(playButton, 0, 0, this);
} else if (part == 1) {
System.out.println("1");
g.setColor(Color.RED);
g.fillRect(0, 0, 40, 40);
}
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (part == 0) {
System.out.println("a");
part = 1;
repaint();
}
}
public void mouseReleased(MouseEvent e) {
}
}
In Java an if statement only affects one statement after the head of the statement. So you need to put the entire body in {}.
if(part == 0){
System.out.println("0");
g.drawImage( playButton, 330, 200, 294, 102, this);
}
Related
The questions says it all really, I want the make the background of a JTextField semi-transparent and I am using a timer to make it flash.
So I have found that using the traditional textField.setBackground() yeilds a strange graphical glitch where with each flash the text field is darker than it should be. (see below)
strange graphical glitch
So after searching online I tried to override the paint method of the JTextField with the following code:
name = new JTextField(15) {
#Override
protected void paintComponent(Graphics g) {
g.setColor(this.getBackground());
g.fillRect(getX(), getY(), getWidth(), getHeight());
super.paintComponent(g);
}
};
Also, some recommended that I set the text field opaque boolean to false. This I did and to no avail, now there is not even any red flashing and I simply get this:
fields with field.setOpaque(false);
Just in case it helps, here is the code I am using to make the fields flash.
public void flashField(JTextField field, Color flashColor, final int flashDelay, final int numberOfFlashes) {
timers.add(new Timer(flashDelay, new ActionListener() {
int counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
counter++;
if (counter % 2 == 0)
field.setBackground(
new Color(flashColor.getRed(), flashColor.getBlue(), flashColor.getGreen(), 50));
else
field.setBackground(Color.WHITE);
if (counter == (numberOfFlashes * 2) + 1) {
((Timer) e.getSource()).stop();
}
field.repaint();
}
}));
timers.get(timers.size() - 1).start();
}
So after searching online I tried to override the paint method
Also, some recommended that I set the text field opaque boolean to false.
Well you need to do both at the same time. Something like:
JPanel panel = new JPanel()
{
protected void paintComponent(Graphics g)
{
g.setColor( getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
panel.setOpaque(false); // background of parent will be painted first
panel.setBackground( new Color(255, 0, 0, 20) );
frame.add(panel);
Check out Background With Transparency for why this is necessary and for a simple reusable solution that you can use on any component without doing custom painting every time.
Here is an adapted code where Textfield keeps on flashing every 200ms and is transparent.
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TransparentTextFieldExample {
public static void main(String[] args) {
new TransparentTextFieldExample();
}
public TransparentTextFieldExample() {
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());
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
TransparentTextField ttf = new TransparentTextField("Some text!", 20);
panel.add(ttf);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
flashField(ttf, Color.RED, 1, 20);
}
});
}
public void flashField(JTextField field, java.awt.Color flashColor, final int flashDelay, final int numberOfFlashes) {
Timer tm = new Timer(flashDelay, new ActionListener() {
int counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
if (counter % 2 == 0) {
field.setBackground(flashColor);
} else {
field.setBackground(Color.WHITE);
}
if (counter == (numberOfFlashes * 2) + 1) {
System.out.println("Inside");
//((Timer) e.getSource()).stop();
// break;
}
field.repaint();
try {
Thread.sleep(200l);
} catch (Exception ex) {
}
counter++;
}
});
tm.start();
}
public class TransparentTextField extends JTextField {
public TransparentTextField(String text) {
super(text);
init();
}
public TransparentTextField(int columns) {
super(columns);
init();
}
public TransparentTextField(String text, int columns) {
super(text, columns);
init();
}
protected void init() {
setOpaque(false);
}
#Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
super.paint(g2d);
g2d.dispose();
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g2d);
g2d.dispose();
}
}
}
I have a program which is simple in function. On start, it creates a random circle which it places in the window/frame. When that circle is clicked, it should dissappear, and spawn a new circle elsewhere. the issue is, my program does this, but you see all the past circles unless you minimize/reopen the window. I cannot get it to repaint without my help... and I do NOT know why. Here is my code.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
public class Core extends JFrame implements MouseListener{
public static ArrayList<Ellipse2D> list = new ArrayList<Ellipse2D>();
Random r = new Random();
public Ellipse2D spawn(){
int x = r.nextInt(this.getWidth());
int y = r.nextInt(this.getHeight());
while(x<75||x>this.getWidth()-150){
x = r.nextInt(this.getWidth());
}
while(y<75||y>this.getHeight()-150){
y = r.nextInt(this.getHeight());
}
System.out.println("MAKING SHAPE at :" + x + " AND " + y);
return new Ellipse2D.Double(x, y, 75, 75);
}
public void mouseClicked(MouseEvent me) {
// Save the coordinates of the click lke this.
if(list.get(0).contains(me.getPoint())){
System.out.println("CLICKED SHAPE!");
list.clear();
list.add(spawn());
}
revalidate();
repaint();
}
public void mouseEntered(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
#Override
public void paint(Graphics g) {
if(list.size()==0){
System.out.println("oops");
}
if(!list.isEmpty()){
System.out.println("DRAW");
int x =(int) list.get(0).getX();
int y =(int) list.get(0).getY();
int width = (int) list.get(0).getWidth();
int height = (int) list.get(0).getHeight();
g.setColor(Color.red);
g.drawOval(x,y, width, height);
}
}
public Core(){
setSize(500, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addMouseListener(this);
list.add(spawn());
setVisible(true);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new Core();
}
});
}
}
Your code works perfectly fine for me, however...
Don't override paint of top level containers like JFrame, JFrame contains a JRootPane, which contains a contentPane and may also have a visible glassPane, all of which can overpaint what is painted within the paint method. As a general rule, you shouldn't extend from JFrame (or other top level containers), you are locking yourself into a single use case, reducing the re-usability of your component and you're not actually any new functionality to the class. Instead, use a JPanel and override it's paintComponent method
Call super.paint before doing any custom painting. If, however, you use a JPanel, call super.paintComponent. Painting is performed by a series of methods which are chained together to generate the final output. See Painting in AWT and Swing and Performing Custom Painting for more details
Consider using something like x = r.nextInt(this.getWidth() - 150) + 75; and y = r.nextInt(this.getWidth() - 150) + 75; instead of your while loops, I think you might find them safer to use
For example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Core {
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new Core();
}
});
}
public Core() {
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 CorePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class CorePane extends JPanel {
private ArrayList<Ellipse2D> list = new ArrayList<Ellipse2D>();
private Random r = new Random();
public Ellipse2D spawn() {
int x = r.nextInt(this.getWidth());
int y = r.nextInt(this.getHeight());
x = r.nextInt(this.getWidth() - 150) + 75;
y = r.nextInt(this.getWidth() - 150) + 75;
System.out.println("MAKING SHAPE at :" + x + " AND " + y);
return new Ellipse2D.Double(x, y, 75, 75);
}
public CorePane() {
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent me) {
// Save the coordinates of the click lke this.
if (list.get(0).contains(me.getPoint())) {
list.clear();
list.add(spawn());
}
revalidate();
repaint();
}
});
}
#Override
public void invalidate() {
super.invalidate();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (list.isEmpty()) {
list.add(spawn());
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (!list.isEmpty()) {
for (Ellipse2D ellipse : list) {
g2d.setColor(Color.red);
g2d.draw(ellipse);
}
}
g2d.dispose();
}
}
}
Or, based on what I believe you're trying to do, you could simply do something like...
public class CorePane extends JPanel {
private Random r = new Random();
private Ellipse2D ellipse;
public Ellipse2D spawn() {
int x = r.nextInt(this.getWidth());
int y = r.nextInt(this.getHeight());
x = r.nextInt(this.getWidth() - 150) + 75;
y = r.nextInt(this.getWidth() - 150) + 75;
System.out.println("MAKING SHAPE at :" + x + " AND " + y);
return new Ellipse2D.Double(x, y, 75, 75);
}
public CorePane() {
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent me) {
if (ellipse != null && ellipse.contains(me.getPoint())) {
ellipse = spawn();
}
revalidate();
repaint();
}
});
}
#Override
public void invalidate() {
super.invalidate();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
spawn();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (ellipse != null) {
g2d.setColor(Color.red);
g2d.draw(ellipse);
}
g2d.dispose();
}
}
I've been trying to work this code, it's like when you hover over the start button it should change its color to gray, but whenever i hover over it. nothing happens, can somebody tell me why? i didn't get any error and it seems like my mousemoved listener isn't recognized by the compiler, sorry for my english. I haven't finish it yet but here is the code:
class Contents extends JFrame implements Runnable {
private Image dbi;
private Graphics dbg;
private boolean isStarted, isHovered;
private int x,y,xDir,yDir,bx,by,timer,life,my,mx,mhx,mhy;
private Rectangle startgame = new Rectangle(80,100,150,40);
Contents()
{
super();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
if(isStarted)
setSize(600,600);
else
{
setSize(300,300);
setBackground(Color.BLUE);
}
setLocationRelativeTo(null);
isStarted = false;
isHovered = false;
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
mx = e.getX();
my = e.getY();
if(mx > startgame.x && mx < startgame.x+startgame.width &&
my > startgame.y && my < startgame.y+startgame.height)
{
isStarted = true;
}
}
public void mouseMoved(MouseEvent e)
{
mhx = e.getX();
mhy = e.getY();
if(mhx > startgame.x && mhx < startgame.x+startgame.width &&
mhy > startgame.y && mhy < startgame.y+startgame.height)
isHovered = true;
else
isHovered = false;
}
});
}
public void paint(Graphics g)
{
dbi = createImage(getWidth(), getHeight());
dbg = dbi.getGraphics();
draw(dbg);
g.drawImage(dbi,0,0,this);
repaint();
}
public void draw(Graphics g)
{
if(!isStarted)
{
if(!isHovered)
g.setColor(Color.GRAY);
else
g.setColor(Color.GREEN);
g.fillRect(startgame.x, startgame.y, startgame.width, startgame.height);
g.setFont(new Font("Serif",Font.BOLD,24));
g.setColor(Color.WHITE);
g.drawString("Start game", startgame.x+20, startgame.y+25);
g.drawString(String.format("hoverx: %d hovery: %d",mhx,mhy), 50,200);
}
else
{
}
}
public void run()
{
} }
public class Game {
public static void main(String[] args)
{
Contents c = new Contents();
} }
Just use Rectangle.contains(Point) to check if the point from the MouseEvent is inside the Rectangle. Here is an example
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PaintedButton extends JPanel {
private static final Color HOVER_COLOR = Color.BLUE;
private static final Color NON_HOVER_COLOR = Color.GREEN;
private static final Rectangle2D RECTANGLE = new Rectangle2D.Double(50, 50,
200, 100);
private Color color = NON_HOVER_COLOR;
public PaintedButton() {
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
Point p = e.getPoint();
if (RECTANGLE.contains(p)) {
color = HOVER_COLOR;
} else {
color = NON_HOVER_COLOR;
}
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(color);
g2.fill(RECTANGLE);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PaintedButton());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
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...
Ok, so what i want is the rectangle to always be moving, but when you press the left and right arrow is changes the direction by either increasing or decreasing the angle. With this code the sqaure moves as it should in the correct direction, but when i press the keys the direction does not change.
import java.awt.*;
import java.awt.Color;
import javax.swing.Timer;
import javax.swing.*;
import java.awt.Graphics;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyAdapter;
public class Fields extends JPanel implements ActionListener, KeyListener{
Timer tm = new Timer(5, this);
double x = 250, y = 250, vel = 0.2, angle = 90;
public void paintComponent(Graphics g)
{
super.paintComponent(g);
this.setBackground(Color.BLACK);
g.setColor(Color.GREEN);
g.fillRect((int)x, (int)y, 5, 5);
tm.start();
}
public void keyTyped(KeyEvent e)
{
if (e.getKeyCode() == 37) {angle--;}
if (e.getKeyCode() == 39) {angle++;}
}
public void keyReleased(KeyEvent e)
{
if (e.getKeyCode() == 37) {angle--;}
if (e.getKeyCode() == 39) {angle++;}
}
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == 37) {angle--;}
if (e.getKeyCode() == 39) {angle++;}
}
public void actionPerformed(ActionEvent e)
{
x += (velX * (float)Math.cos(Math.toRadians(angle - 90)));
y += (velX * (float)Math.sin(Math.toRadians(angle - 90)));
repaint();
}
public Fields()
{
this.addKeyListener(this);
}
public static void main(String[] args)
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(500, 500);
Fields fi = new Fields();
f.add(fi);
f.setVisible(true);
}
}
As started in my comments...
Don't start the timer in paintComponent, this method gets called repeatedly and can be called often in quick succession.
Use key bindings
.
public class TestAnimation01 {
public static void main(String[] args) {
new TestAnimation01();
}
public TestAnimation01() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new Fields());
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Fields extends JPanel implements ActionListener {
Timer tm = new Timer(125, this);
double x = 250, y = 250, vel = 0.2, angle = 90;
private int velX = 4;
private int velY = 4;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.BLACK);
g.setColor(Color.GREEN);
g.fillRect((int) x, (int) y, 5, 5);
}
public void actionPerformed(ActionEvent e) {
x += (velX * (float) Math.cos(Math.toRadians(angle - 90)));
y += (velX * (float) Math.sin(Math.toRadians(angle - 90)));
repaint();
}
public Fields() {
setFocusable(true);
InputMap im = getInputMap(WHEN_FOCUSED);
ActionMap am = getActionMap();
// left 37
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "goLeft");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "goRight");
am.put("goLeft", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
angle--;
repaint();
}
});
am.put("goRight", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
angle++;
repaint();
}
});
tm.setRepeats(true);
tm.setCoalesce(true);
tm.start();
requestFocusInWindow();
}
}
}
There's a bunch of other things you've not covered, such as edge conditions (what happens when it leaves the screen) and individual x/y speeds, but I'm sure you'll work it out