发布我的方法,使二维圆在圆中移动



OBS!更改为问题的一部分已得到回答。

由于您的帮助和输入,我的数学已经修复,与StackOverflowError相同,但我仍然可以思考如何使圆从一个x,y点移动到另一个。目前我只是在多个地方重复绘制。

public class MyFrame extends JPanel {
int xc = 300, yc = 300, r = 100, diam = 50;
double inc = Math.PI / 360, theta = 0;
public void paintComponent(Graphics g) {
Timer timer = new Timer(0, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
theta = theta + inc;
repaint();
}
});
timer.setDelay(2);
timer.start();
}
@Override
public void paint(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); //smooth the border around the circle
g2d.rotate(theta, xc, yc);
g2d.setColor(Color.blue);
g2d.drawOval(xc + r - diam / 2, yc + r - diam / 2, diam, diam);
paintComponent(g);
}
}

这应该有助于您入门。您可以根据需要对其进行修改。它只是有一个围绕面板中心的内部红点旋转的外圈。

  • 首先,旋转图形上下文,而不是围绕中心旋转圆的位置。因此,不需要触发器
  • Anti-aliasing只是欺骗眼睛,让他们认为图形更平滑
  • BasicStroke设置线条的厚度
  • 你需要把面板放在一个框架里
  • 并且CCD_ 3应该是CCD_
  • 计时器通过增量更新角度并调用重新绘制。一个较大的增量将使一个更快但更"大"的;肉干;围绕中心的运动。如果将角度设置为Math.PI/4,则需要增加计时器延迟(尝试约1000ms)
  • 有关绘画的更多信息,请查看Java教程
  • 我遗漏或忘记的任何其他内容都应该记录在JavaDocs中
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class DrawCircle extends JPanel {
int width = 500, height = 500;
final int xc = width/2, yc = height/2;
int r = 100; // radius from center of panel to center of outer circle
int diam = 50; // outer circle diamter
double inc = Math.PI/360; 
double theta = 0;
JFrame f = new JFrame();
public static void main(String[] args) {
SwingUtilities.invokeLater(()-> new DrawCircle().start());
}
public void start() {
f.add(this);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.setVisible(true);
Timer timer = new Timer(0, (ae)-> { theta += inc; repaint();});
timer.setDelay(20);
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
g2d.rotate(theta, xc, yc);
g2d.setColor(Color.red);
g2d.fillOval(xc-3, yc-3, 6, 6); // center of panel
g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.blue);
//      g2d.drawLine(xc,yc, xc+r, yc); // tether between centers 
g2d.drawOval(xc+r-diam/2, yc-diam/2, diam,diam);
}
}

更新的答案

好吧,有两件基本的事情你做错了。

  • 您没有将super.paintComponent(g)添加为paintComponent方法中的第一条语句
  • 您正在重写paint(Graphics g)(无论您是否打算),因为它也是公共的,并且由JPanelJComponent继承。不要使用paint(),因为这里没有必要(可能在某些应用程序中,但我从未有过这种需要)。将其中的所有代码移动到paintComponent

您还应该将计时器代码移到paintComponent之外。它只需要定义一次,并且在后台运行。它将继续呼叫您的ActionListener class,直到您停止它。

现在,在完成上述操作之后,您可能会问";为什么我画画的时候只有一个圆圈"显而易见的答案是,我只想画一个。但为什么不每次都重复呢?

因为每次调用paintComponent时,super.paintComponent(g)都会按预期清除JPanel。因此,如果你想画多个圆(或其他东西),你需要把它们放在一个列表中,并从paintComponent中的中画出来。由于包括绘画和计时器在内的所有事件都是在一个线程(事件调度线程)上串行运行的,因此将处理降至最低是很重要的。因此,在可能的情况下,大多数计算都应该在该线程之外进行。EDT processing should be as simple and as quick as possible.

我的第一个答案显示了一个围绕一个点旋转的圆圈。但也许这不是你想要的。您可能只想以固定距离均匀地围绕中心放置圆。我提供了两种方法。

  • 像以前一样使用旋转。伊莫,这是最简单的。角度是固定的,每次旋转都被称为加法。所以只需要调用nCircle次这个方法并画一个圆。记住计算x and y坐标来校正半径
  • 使用trig来计算圆的位置。这使用了一个基于nCircles的角度列表。对于每次迭代,基于半径和当前角度来计算x and y

这两者都以不同的颜色显示,以展示它们的叠加效果。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class DrawCircle2 extends JPanel {
int width = 500, height = 500;
final int xc = width / 2, yc = height / 2;
int r = 100; // radius from center of panel to center of outer circle
int diam = 50; // outer circle diamter
int nCircles = 8; // number of circles

double theta = Math.PI*2/nCircles;

List<Point> coords1 = fillForTrig();
JFrame f = new JFrame();

public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new DrawCircle2().start());
}

private List<Point> fillForTrig() {
List<Point> list = new ArrayList<>();
for (int i = 0; i < nCircles; i++) {
int x = xc+(int)(r*Math.sin(i*theta));
int y = yc+(int)(r*Math.cos(i*theta));
list.add(new Point(x,y));
}
return list;
}


public void start() {

f.add(this);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.setVisible(true);
}

public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawUsingRotate(g2d);
//      drawUsingTrig(g2d);
}
private void drawUsingRotate(Graphics2D g2d) {
g2d = (Graphics2D)g2d.create();
g2d.setColor(Color.RED);
//fixed positions for radius as context is rotated
int xx =  0;
int yy  = r;
for (int i = 0; i < nCircles;i++) {
g2d.rotate(theta, xc, yc);
// xx-diam/2 just places the center of the orbiting circle at
// the proper radius from the center of the panel. Same for yy.
g2d.drawOval(xc + xx - diam / 2, yc + yy - diam / 2, diam,
diam);

}
g2d.dispose();
}
private void drawUsingTrig(Graphics2D g2d) {
g2d = (Graphics2D)g2d.create();
g2d.setColor(Color.BLUE);
for (Point p : coords1) {
int x = (int)p.getX();
int y = (int)p.getY();
g2d.drawOval(x-diam/2, y-diam/2, diam, diam);
}
g2d.dispose();
}
}

Math.sinMath.cos方法需要以弧度为单位的值。您可以通过乘以Math.PI/180将度数转换为弧度

因此,请尝试将Math.cos(i * 360 / n)Math.sin(i * 360 / n)更改为Math.cos((i * 360 / n)*(Math.PI/180))super.paintComponent(g)0。

最新更新