问题描述
我已经制作了这个太阳系,到目前为止我已经完成了制作这个代码。 如图所示,我想使用 public static class SolarCv extends JComponent 而不是使用 public static class SolarCv extends JPanel,但它不起作用。我应该在代码中更改什么以及如何添加围绕对象的轨道,如图所示?
package solar;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
public class Orbit {
public static class SolarCv extends JComponent {
int width;
int height;
public SolarCv(int width,int height) {
this.width = width;
this.height = height;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(width,height);
}
@Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
// Clear the background.
g2.setColor(getBackground());
g2.fillRect(0,getWidth(),getHeight());
// Sun transform. Just centre it in the window.
AffineTransform StarSun = AffineTransform.getTranslateInstance(getWidth() / 2,getHeight() / 2);
// Draw the sun
g2.setTransform(StarSun);
SuperStar(g2,80,Color.YELLOW);
// Orbital period.
// One rotation every 10s.
double percentRotation = System.currentTimeMillis() % 10000 / 10000.0;
// To radians.
double angle = -Math.PI * 2 * percentRotation;
// Earth transform.
// Set the orbital radius to 1/3rd the panel width
AffineTransform StarEarth = AffineTransform.getTranslateInstance(getWidth() / 4,0);
// Rotate
StarEarth.preConcatenate(AffineTransform.getRotateInstance(angle));
// Add the sun transform
StarEarth.preConcatenate(StarSun);
// Draw the earth
g2.setTransform(StarEarth);
SuperStar(g2,40,Color.BLUE);
// Moon transform.
// Set the orbital radius to 1/10th the panel width
AffineTransform StarMoon = AffineTransform.getTranslateInstance(getWidth() / 10,0);
// Rotate
StarMoon.preConcatenate(AffineTransform.getRotateInstance(angle));
// Add the earth transform (already includes the sun transform)
StarMoon.preConcatenate(StarEarth);
// Draw the moon
g2.setTransform(StarMoon);
SuperStar(g2,20,Color.DARK_GRAY);
}
private void SuperStar(Graphics2D g2,int size,Color color) {
g2.setColor(color);
g2.filloval(-size / 2,-size / 2,size,size);
}
}
public static void main(String[] args) throws IOException,InterruptedException {
JFrame Solarsys = new JFrame("Orbit");
Solarsys.setDefaultCloSEOperation(WindowConstants.EXIT_ON_CLOSE);
JComponent SolarCv = new SolarCv(500,500);
Solarsys.add(SolarCv);
Solarsys.pack();
Solarsys.setVisible(true);
while (true) {
Thread.sleep(20);
SolarCv.repaint();
}
}
}
解决方法
我发现你的作业很有趣,所以我创建了以下 GUI。
简介
我无法制作太阳、地球和月亮的相对大小,因为它们不适合显示器。
我无法将太阳、地球和月亮的相对距离分开,因为它们不适合显示器。
但是,我可以使地球和月球的旋转速度相互关联。
那么,我是怎么做到的?
由于这是一项作业,我不会提供我的全部代码。我将解释我如何编写我的代码和一些代码片段,希望它在未来对 OP 和其他人有所帮助。
说明
通常,当您创建 Swing GUI 时,您应该使用 model / view / controller 模式。这种模式允许您将关注点分开,并一次专注于应用程序的一个部分。
我编写了五个 Java 类来创建这个 GUI。我写了两个模型类、两个视图类和一个控制器类。控制器类有一个额外的匿名类。
型号
我编写的第一个模型类是 Body
类。这个类是一个计划Java getter / setter 类。
Body
类包含一个 java.awt.Point
标记身体的中心,身体半径 int
像素,轨道半径 int
像素,以度为单位的 theta 角增量和体色。
现在,地球轨道应该是地球实例的一部分。但是,我发现将地球轨道作为太阳实例的一部分更容易。这是您的代码没有反映现实以便您可以更准确地模拟现实的情况之一。
我花了一段时间才想出适合地球和月球的 theta 角增量。我只给你我的方程式,因为我花了大约 15 分钟尝试不同的函数。
sun thetaIncrement = 625_000.0 / framesPerSecond / 365.25 / 360.0
earth thetaIncrement = 625_000.0 / framesPerSecond / 27.3 / 360.0
625,000 是一个“神奇”的数字,它使动画以合理的速度移动。 360 度是一个圆的度数。
这两个公式之间的唯一区别是进行完整旋转的天数的值。
Body
类有一个有趣的方法,即 getOrbitPoint
方法。基本上,getOrbitPoint
方法将极坐标转换为笛卡尔坐标。很简单,但我会把代码贴出来。
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);
}
正值 thetaIncrement
将使主体顺时针旋转。负 thetaIncrement
将使主体逆时针旋转。
我创建的第二个模型类是 SolarSystemModel
类。这个类是一个普通的 Java getter/setter 类。
SolarSystemModel
类保存显示面板像素数的 int
值、动画每秒帧数的 int
值和 {{1} } Body 实例。
我创建了一个工厂方法来创建三个 java.util.List
实例,即太阳、地球和月亮。这是代码片段。
Body
查看
我创建了两个类,一个用于 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,Color.BLUE);
bodies.add(body);
point = body.getOrbitPoint();
body = new Body(point.x,10,0.0,Color.WHITE);
bodies.add(body);
return bodies;
}
,另一个用于绘图 JFrame
。我发布了这两个类的代码,而不是冗长的解释。
JPanel
当您创建适当的应用程序模型时,您可以看到视图类变得多么简单。
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);
}
}
}
方法创建 run
和绘图的一个实例 JFrame
。
绘图 JPanel
绘制了 JPanel
实例。 期间。绘图 Body
没有尝试做任何其他事情。
JPanel
Graphics
方法绘制椭圆并根据左上角填充它。我们做了一些数学运算,这样我们就可以根据中心点绘制椭圆了。
控制器
只有一个控制器类,fillOval
类。
Animation
类暂停 5 秒,然后开始地球和月球的自转。由于我们已经完成了创建模型和视图的工作,因此 Animation 类也很简单。
由于我使用的是老式 Animation
,所以我将在此处发布课程。
Runnable
结论
我希望这个解释有帮助。使用模型/视图/控制器模式。分开你的顾虑。一次专注于应用程序的一个部分。确保每个类方法都做一件事。