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)
(无论您是否打算),因为它也是公共的,并且由JPanel
从JComponent
继承。不要使用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.sin
和Math.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。