I have a paint
method that I have draw a rectangle and move it across the screen and what I want it to do I when the rectangle goes off the screen to move it back to the start of the JFrame. I assume it would be something like if(rectangle.isoffthescreen){ put it back on the screen }
but I don't know how to do that. Also, I want to know if you can do something to the rect like JFrame frame = new JFrame();
, but for obviously for the rectangle. I'm sorry if this is confusing.
@MadProgrammer Here is where I am at so far
public class main extends JPanel {
public static int place = -350;
public Rectangle rect;
public int xDelta;
public main() {
rect = new Rectangle(0, 75, 50, 50);
xDelta = 4;
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
rect.x += xDelta;
if (rect.x + rect.width > getWidth() - 1) {
rect.x = getWidth() - rect.width;
xDelta *= -1;
} else if (rect.x < 0) {
rect.x = 0;
xDelta *= -1;
}
repaint();
}
});
timer.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g.create();
Random r = new Random();
int r1;
r1 = r.nextInt(5);
if (r1 == 0) {
g2d.setColor(Color.WHITE);
} else if (r1 == 1) {
g2d.setColor(Color.BLUE);
} else if (r1 == 2) {
g2d.setColor(Color.RED);
} else if (r1 == 3) {
g2d.setColor(Color.GREEN);
} else if (r1 == 4) {
g2d.setColor(Color.PINK);
} else {
g2d.setColor(Color.CYAN);
}
place += 50;
rect = new Rectangle(place, 100, 300, 200);
g2d.draw(rect);
g2d.fill(rect);
g2d.dispose();
try {
Thread.sleep(400);
} catch (Exception e) {
}
repaint();
}
}
and
public class frame {
public static JFrame frame;
public static void main(String args[]){
frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//frame.setResizable(false);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
main m = new main();
m.setBackground(Color.BLACK);
frame.add(m);
}
}
I still can't get it to work.
First of, you should avoid overriding paint
of top level containers and instead use something the extends from JComponent
(like JPanel
) and override it's paintComponent
.
There are a number of reasons, but in your case, the frame contains a decoration which sits inside the viewable area.
The basic process would be to check edge cases...
if (box.x + box.width > getWidth() - 1) {
// The boxes right edge is beyond the right edge of it's container
} else if (box.x < 0) {
// The boxes left edge is beyond the left edge of it's container
}
This checks to see if the box
's right edge is beyond the containers right edge and if the box
's left edge is beyond the left edge of the container.
It would be a simple process to included vertical checking as well.
Updated with example
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.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Move {
public static void main(String[] args) {
new Move();
}
public Move() {
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 Rectangle box;
private int xDelta;
public TestPane() {
box = new Rectangle(0, 75, 50, 50);
xDelta = 4;
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
box.x += xDelta;
if (box.x + box.width > getWidth() - 1) {
box.x = getWidth() - box.width;
xDelta *= -1;
} else if (box.x < 0) {
box.x = 0;
xDelta *= -1;
}
repaint();
}
});
timer.start();
}
@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.BLUE);
g2d.fill(box);
g2d.dispose();
}
}
}
Update from OP's example code
Immediately, a number of things worry me...
paint
Thread.sleep
in the paint
methodrepaint
from within the paint
methodRectangle
in the paint
methodplace
variableCheck out Performing Custom Painting for more details about painting in Swing
You should never block or perform long running processing the Event Dispatching Thread, this will prevent the EDT from processing (amongst other things) paint requests and new events. By calling Thread.sleep
in the paint
method, you are preventing Swing from updating the screen.
Check out Concurrency in Swing for more details.
Calling repaint
(or any method that might call repaint
) within a paint
method is a sure way to consume you CPU cycle.
You may want to check out Painting in AWT and Swing for more details about the paint process in Swing
By creating a new Rectangle
in the paint
method, you are throwing away any changes that the Timer
has made, effectively stopping you rectangle from moving effectively...
The place
method is not required. Animation is the illusion of change over time, hence the use of the Timer
and xDelta
.
Updated based on your code example
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.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Move {
public static void main(String[] args) {
new Move();
}
public Move() {
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 Main());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class Main extends JPanel {
public static int place = -350;
public Rectangle rect;
public int xDelta;
public Main() {
rect = new Rectangle(0, 75, 50, 50);
xDelta = 4;
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
rect.x += xDelta;
if (rect.x + rect.width > getWidth() - 1) {
rect.x = getWidth() - rect.width;
xDelta *= -1;
} else if (rect.x < 0) {
rect.x = 0;
xDelta *= -1;
}
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Random r = new Random();
int r1;
r1 = r.nextInt(5);
if (r1 == 0) {
g2d.setColor(Color.WHITE);
} else if (r1 == 1) {
g2d.setColor(Color.BLUE);
} else if (r1 == 2) {
g2d.setColor(Color.RED);
} else if (r1 == 3) {
g2d.setColor(Color.GREEN);
} else if (r1 == 4) {
g2d.setColor(Color.PINK);
} else {
g2d.setColor(Color.CYAN);
}
// place += 50;
// rect = new Rectangle(place, 100, 300, 200);
g2d.draw(rect);
g2d.fill(rect);
g2d.dispose();
}
}
}