问题
I am trying to make a program that starts with 7 circles at the top of a JPanel. All the circles have a random size and color. The circles start at the top of the screen and move downwards once they reach the bottom of the JPanel they should reappear at the top of the JPanel and move downwards again. I can already make the circles move downwards but I am unsure of how to draw them back at the top again. I made a method called replaceCircle to use to draw the circles back at the top of the JPanel but its not working.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.util.Random;
import javax.swing.JPanel;
import javax.swing.Timer;
public class keyExample extends JPanel implements ActionListener, KeyListener {
private Circle[] circles = new Circle[7];
Timer t = new Timer(5, this);
//current x and y
double x = 150, y = 200;
double changeX = 0, changeY = 0;
private Circle c1, c2, c3, c4, c5, c6, c7, circleone;
private int circlex = 10, circley = 0; // makes initial starting point of circles 0
private int newCirclex = 0, newCircley = 0;
private javax.swing.Timer timer2;
private Random num = new Random();
private int s = num.nextInt(8);
public keyExample() {
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
Random num = new Random();
Random colors = new Random();
Color color1 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
Color color2 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
Color color3 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
Color color4 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
Color color5 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
Color color6 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
Color color7 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
int radius1 = num.nextInt(40);
int radius2 = num.nextInt(20);
int radius3 = num.nextInt(25);
int radius4 = num.nextInt(45);
int radius5 = num.nextInt(15);
int radius6 = num.nextInt(40);
int radius7 = num.nextInt(50);
if (radius1 < 5) {
radius1 = 10;
} else if (radius2 < 5) {
radius2 = 10;
} else if (radius3 < 5) {
radius3 = 10;
} else if (radius4 < 5) {
radius4 = 10;
} else if (radius5 < 5) {
radius5 = 10;
} else if (radius6 < 5) {
radius6 = 10;
} else if (radius7 < 5) {
radius7 = 10;
} else {
}
c1 = new Circle(circlex, circley, radius1, color1);
c2 = new Circle(circlex + 70, circley, radius2, color2);
c3 = new Circle(circlex + 150, circley, radius3, color3);
c4 = new Circle(circlex + 220, circley, radius4, color4);
c5 = new Circle(circlex + 270, circley, radius5, color5);
c6 = new Circle(circlex + 340, circley, radius6, color6);
c7 = new Circle(circley + 410, circley, radius7, color7);
circles[0] = c1;
circles[1] = c2;
circles[2] = c3;
circles[3] = c4;
circles[4] = c5;
circles[5] = c6;
circles[6] = c7;
timer2 = new javax.swing.Timer(33, new MoveListener());
timer2.start();
}
public void NewCircle() {
for (int i = 0; i < circles.length; i++) {
Random num = new Random();
Random colors = new Random();
Color color = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
int radius = num.nextInt(40);
if (radius < 5) {
radius = radius + 10;
} else {
}
circles[i] = new Circle(circlex, circley, radius, color);
}
}
public void replaceCircle() {
int height = getHeight();
newCircley = newCircley + s;
circley = newCircley;
Random num = new Random();
int radius = num.nextInt(34);
Random colors = new Random();
Color color = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
if (circley > height) {
c1 = new Circle(10, 0, radius, color);
} else {
}
}
public void createCircle() {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLUE);
g2.fill(new Rectangle2D.Double(x, y, 40, 40));
for (int i = 0; i < circles.length; i++) {
circles[i].fill(g);
}
}
public void actionPerformed(ActionEvent e) {
repaint();
x += changeX;
y += changeY;
changeX = 0;
changeY = 0;
}
public void up() {
if (y != 0) {
changeY = -3.5;
changeX = 0;
}
}
public void down() {
if (y <= 350) {
changeY = 3.5;
changeX = 0;
}
}
public void left() {
if (x >= 0) {
changeX = -3.5;
changeY = 0;
}
}
public void right() {
if (x <= 550) {
changeX = 3.5;
changeY = 0;
}
}
private class MoveListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
Random speed = new Random();
int s2 = speed.nextInt(12);
int s3 = speed.nextInt(4);
int s4 = speed.nextInt(20);
int s5 = speed.nextInt(7);
int s6 = speed.nextInt(5);
int s7 = speed.nextInt(8);
c1.move(0, s);
c2.move(0, s2);
c3.move(0, s3);
c4.move(0, s4);
c5.move(0, s5);
c6.move(0, s6);
c7.move(0, s7);
repaint();
}
}
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_RIGHT) {
right();
}
if (code == KeyEvent.VK_LEFT) {
left();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public static void main(String[] args) {
new keyExample();
}
}
Circle Class
import java.awt.*;
public class Circle {
private int centerX, centerY, radius, coord;
private Color color;
public Circle(int x, int y, int r, Color c) {
centerX = x;
centerY = y;
radius = r;
color = c;
}
public void draw(Graphics g) {
Color oldColor = g.getColor();
g.setColor(color);
g.drawOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.setColor(oldColor);
}
public void fill(Graphics g) {
Color oldColor = g.getColor();
g.setColor(color);
g.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.setColor(oldColor);
}
public boolean containsPoint(int x, int y) {
int xSquared = (x - centerX) * (x - centerX);
int ySquared = (y - centerY) * (y - centerY);
int RadiusSquared = radius * radius;
return xSquared + ySquared - RadiusSquared <= 0;
}
public void move(int xAmount, int yAmount) {
centerX = centerX + xAmount;
centerY = centerY + yAmount;
}
}
回答1:
The better solution would be providing the Circle
with some means to determine what it should do when it moves out of bounds, however, the code is so convoluted I used this instead...
Start by adding a getBounds
method to your Circle
class...
public Rectangle getBounds() {
int x = centerX - radius;
int y = centerY - radius;
return new Rectangle(x, y, radius * 2, radius * 2);
}
This will provide information about how big and where the circle is...
Next, in your MoveListener
, add a checkBounds
method...
public void checkBounds(Circle circle) {
int height = getHeight();
Rectangle bounds = circle.getBounds();
if (bounds.y + bounds.height > height) {
circle.move(0, -(height) + bounds.height);
}
}
This will be used to determine if a given Circle
has moved beyond the bounds of the viewable area...
Next, in your MoveListener
's actionPerformed
method, check each circle...
c1.move(0, s);
checkBounds(c1);
As so on...
Updated with quick and fast example
So, this is quick and fast example of what I've being trying to get to...

This uses an ArrayList
as the primary container for the Circles
, but it wouldn't take much to change it to use an array (in fact, some parts would become easier)....
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.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
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 DropCircles {
public static void main(String[] args) {
new DropCircles();
}
public DropCircles() {
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 static class TestPane extends JPanel {
protected static final int MAX_CIRCLES = 7;
private List<Circle> circles;
private Random rnd = new Random();
public TestPane() {
circles = new ArrayList<>(MAX_CIRCLES);
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
while (circles.size() < MAX_CIRCLES) {
circles.add(createCircle());
}
List<Circle> purge = new ArrayList<>(MAX_CIRCLES);
for (Circle circle : circles) {
Point p = circle.getLocation();
p.y += circle.getYDelta();
if (p.y > getHeight()) {
purge.add(circle);
} else {
circle.setLocation(p);
}
}
circles.removeAll(purge);
repaint();
}
});
timer.start();
}
protected Circle createCircle() {
int x = rnd.nextInt(getWidth());
int radius = 5 + rnd.nextInt(45);
int speed = 1 + rnd.nextInt(8);
if (x + radius > getWidth()) {
x = getWidth() - radius;
}
Circle circle = new Circle(radius, new Color(rnd.nextInt(255), rnd.nextInt(255), rnd.nextInt(255)));
circle.setLocation(x, 0);
circle.setYDelta(speed);
return circle;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Circle circle : circles) {
circle.paint(g);
}
g2d.dispose();
}
}
public static class Circle {
private final int radius;
private final Color color;
private int x;
private int y;
private int yDelta;
public Circle(int radius, Color color) {
this.radius = radius;
this.color = color;
}
public void setLocation(int x, int y) {
this.x = x;
this.y = y;
}
public void setLocation(Point p) {
setLocation(p.x, p.y);
}
public Point getLocation() {
return new Point(x, y);
}
public void setYDelta(int yDelta) {
this.yDelta = yDelta;
}
public int getYDelta() {
return yDelta;
}
public void paint(Graphics g) {
g.setColor(color);
g.fillOval(x, y, radius, radius);
}
}
}
Basically what happens is, as a Circle
leaves the viewable area, it is removed from the "list" and on the next tick (of the Timer
), a new Circle
is created to ensure that there is always seven circles on the screen (or there abouts).
If you were to use an array. You could simply create a new Circle
in the movement loop at the index position of the current Circle
, effectivly replacing it...
来源:https://stackoverflow.com/questions/20462128/how-can-i-draw-a-circle-again-if-it-goes-too-far-on-a-jpanel