I found your assignment interesting, so I created the following GUI.

Introduction
I couldn't make the sun, earth, and moon relative sizes because they wouldn't fit on a monitor.
I couldn't make the sun, earth, and moon relative distance apart because they wouldn't fit on a monitor.
However, I could make the rotational speeds of the earth and moon relative to each other.
So, how did I do this?
Since this is an assignment, I'm not going to provide my entire code. I will provide an explanation of how I wrote my code and some code snippets in the hopes that it will help the OP and others in the future.
Explanation
Generally, when you create a Swing GUI, you should use the model / view / controller pattern. This pattern allows you to separate your concerns and focus on one part of the application at a time.
I wrote five Java classes to create this GUI. I wrote two model classes, two view classes, and one controller class. The controller class has one additional anonymous class.
Model
The first model class I wrote was the Body
class. This class is a plan Java getter / setter class.
The Body
class contains a java.awt.Point
marking the center of the body, a radius of the body in int
pixels, a radius of the orbit in int
pixels, an increment of the theta angle in degrees, and a body color.
Now, the orbit of the earth should be a part of an earth instance. However, I found it easier to make the earth orbit part of the sun instance. This is one of those cases where your code doesn't reflect reality so that you can model reality more accurately.
It took me a while to come up with the appropriate theta angle increments for the earth and the moon. I'll just give you my equations since I spent about 15 minutes trying different functions.
sun thetaIncrement = 625_000.0 / framesPerSecond / 365.25 / 360.0
earth thetaIncrement = 625_000.0 / framesPerSecond / 27.3 / 360.0
The 625,000 is a "magic" number that makes the animation move at a reasonable speed. The 360 is the number of degrees in a circle.
The only difference between the two formulas is the values for the number of days to make a complete rotation.
The Body
class has one interesting method, the getOrbitPoint
method. Basically, the getOrbitPoint
method converts polar coordinates to cartesian coordinates. It's pretty straightforward, but I'll post the code.
public Point getOrbitPoint() {
double radians = Math.toRadians(theta);
int x = (int) Math.round(Math.cos(radians) *
orbitRadius + center.x);
int y = (int) Math.round(Math.sin(radians) *
orbitRadius + center.y);
theta += thetaIncrement;
theta = (theta > 360.0) ? theta - 360.0 : theta;
theta = (theta < -360.0) ? theta + 360.0 : theta;
return new Point(x, y);
}
A positive thetaIncrement
will make the body rotate clockwise. A negative thetaIncrement
will make the body rotate counter-clockwise.
The second model class I created is the SolarSystemModel
class. This class is a plain Java getter / setter class.
The SolarSystemModel
class holds an int
value for the number of display panel pixels, an int
value for the number of frames per second for the animation, and a java.util.List
of Body instances.
I created a factory method to create three Body
instances, sun, earth, and moon. Here's that code snippet.
private List<Body> createBodyFactory() {
List<Body> bodies = new ArrayList<>();
int c = drawingPanelWidth / 2;
int o = drawingPanelWidth / 3;
double thetaIncrement = 625_000.0 / framesPerSecond / 365.25 / 360.0;
Body body = new Body(c, c, 60, o, thetaIncrement, Color.YELLOW);
bodies.add(body);
Point point = body.getOrbitPoint();
thetaIncrement = 625_000.0 / framesPerSecond / 27.3 / 360.0;
body = new Body(point.x, point.y, 20, 60, thetaIncrement, Color.BLUE);
bodies.add(body);
point = body.getOrbitPoint();
body = new Body(point.x, point.y, 10, 20, 0.0, Color.WHITE);
bodies.add(body);
return bodies;
}
View
I created two classes, one for the JFrame
and one for the drawing JPanel
. Rather than a lengthy explanation, I'm posting the code for those two classes.
public class SolarSystemGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new SolarSystemGUI());
}
private Animation animation;
private DrawingPanel drawingPanel;
private SolarSystemModel model;
public SolarSystemGUI() {
this.model = new SolarSystemModel();
}
@Override
public void run() {
JFrame frame = new JFrame("Solar System");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawingPanel = new DrawingPanel(model);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
this.animation = new Animation(this, model);
new Thread(animation).start();
}
public void repaint() {
drawingPanel.repaint();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private SolarSystemModel model;
public DrawingPanel(SolarSystemModel model) {
this.model = model;
this.setBackground(Color.BLACK);
int width = model.getDrawingPanelWidth();
this.setPreferredSize(new Dimension(width, width));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
List<Body> bodies = model.getBodies();
for (Body body : bodies) {
drawBody(g, body);
}
}
private void drawBody(Graphics g, Body body) {
Point point = body.getCenter();
int radius = body.getRadius();
int x = point.x - radius;
int y = point.y - radius;
int width = radius + radius;
g.setColor(body.getColor());
g.fillOval(x, y, width, width);
}
}
}
You can see how simple the view classes become when you create an appropriate application model.
The run
method creates the JFrame
and one instance of the drawing JPanel
.
The drawing JPanel
draws the Body
instances. Period. The drawing JPanel
doesn't try and do anything else.
The Graphics
fillOval
method draws the oval and fills it in based on the upper left corner. We do a little math so we can draw the oval based on the center point.
Controller
There's only one controller class, the Animation
class.
The Animation
class pauses for 5 seconds, then starts the rotation of the earth and moon. Because of the work we already did creating the model and the view, the Animation class is also straightforward.
Since I used an old-school Runnable
, I'll post the class here.
public class Animation implements Runnable {
private volatile boolean running;
private final SolarSystemGUI frame;
private final SolarSystemModel model;
public Animation(SolarSystemGUI frame, SolarSystemModel model) {
this.frame = frame;
this.model = model;
this.running = true;
}
@Override
public void run() {
sleep(5000L);
long duration = 1000L / model.getFramesPerSecond();
while (running) {
List<Body> bodies = model.getBodies();
Point center = null;
for (Body body : bodies) {
if (center != null) {
body.setCenter(center);
}
center = body.getOrbitPoint();
}
repaint();
sleep(duration);
}
}
private void sleep(long duration) {
try {
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void repaint() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
frame.repaint();
}
});
}
public synchronized void setRunning(boolean running) {
this.running = running;
}
}
Conclusion
I hope this explanation helps. Use the model / view / controller pattern. Separate your concerns. Focus on one part of the application at a time. Make sure each and every class method does one thing.