发布我的方法让 2D 圆圈移动
Issues my method to get a 2D circle to move in a circle
天啊!已更改部分问题已得到解答。
由于您的帮助和输入,我的数学问题已经得到解决,WhosebugError 也是如此,但我仍然可以了解如何使圆从一个 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);
}
}
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))
和 Math.sin((i * 360 / n)*(Math.PI/180))
。
这应该可以帮助您入门。您可以根据需要修改它。它只是有一个外圆围绕面板中心的内部红点旋转。
- 首先,旋转图形上下文,而不是围绕中心的圆圈位置。因此,不需要触发。
Anti-aliasing
只是让眼睛误以为图形更流畅。
BasicStroke
设置线的粗细
- 您需要将面板放在框架中。
- 和
super.paintComponent(g)
应该是 paintComponent
中的第一个语句来清除面板(并做其他事情)。
- 计时器按增量更新角度并调用重绘。较大的增量将使围绕中心的运动更快但更“不稳定”。如果你设置角度为
Math.PI/4
,那么你需要增加定时器延迟(尝试1000ms左右)。
- 查看 Java Tutorials 了解有关绘画的更多信息。
- 我遗漏或忘记的任何其他内容都应记录在 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)
(无论你是否打算),因为它也是 public 并且由 JPanel
从 JComponent
继承。不要使用 paint()
因为这里没有必要(也许在某些应用程序中但我从来没有需要)。将其中的所有代码移动到 paintComponent
您还应该将计时器代码移到 paintComponent
之外。只需要定义一次,在后台是运行。它将继续调用您的 ActionListener class
直到您停止它。
现在,做完上面的你可能会问“为什么我画的时候只出现一个圆圈?”显而易见的答案是我只想画一个。但是为什么每次都不重复呢?
因为 super.paintComponent(g)
每次调用 paintComponent
时都会清除 JPanel
,就像它应该的那样。所以如果你想画多个圆(或其他东西),你需要把它们放在一个列表中,从paintComponent
之内画出来。由于包括绘画和计时器在内的所有事件都是 运行 在单个线程(事件调度线程)上串联的,因此将处理保持在最低限度很重要。因此,如果可能,大多数计算应该在该线程之外完成。 EDT processing should be as simple and as quick as possible.
我的第一个答案是一个圆围绕一个点。但也许那不是你想要的。您可能只想将圆从固定距离均匀地围绕中心放置。我提供了两种方法。
- 像以前一样使用旋转。 Imo,这是最简单的。角度是固定的,每次旋转被调用时,它是累加的。所以只需调用该方法
nCircle
次并绘制圆圈。并记住计算 x and y
坐标以校正半径。
- 使用三角函数计算圆圈的位置。这使用基于
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();
}
}
天啊!已更改部分问题已得到解答。
由于您的帮助和输入,我的数学问题已经得到解决,WhosebugError 也是如此,但我仍然可以了解如何使圆从一个 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);
}
}
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))
和 Math.sin((i * 360 / n)*(Math.PI/180))
。
这应该可以帮助您入门。您可以根据需要修改它。它只是有一个外圆围绕面板中心的内部红点旋转。
- 首先,旋转图形上下文,而不是围绕中心的圆圈位置。因此,不需要触发。
Anti-aliasing
只是让眼睛误以为图形更流畅。BasicStroke
设置线的粗细- 您需要将面板放在框架中。
- 和
super.paintComponent(g)
应该是paintComponent
中的第一个语句来清除面板(并做其他事情)。 - 计时器按增量更新角度并调用重绘。较大的增量将使围绕中心的运动更快但更“不稳定”。如果你设置角度为
Math.PI/4
,那么你需要增加定时器延迟(尝试1000ms左右)。 - 查看 Java Tutorials 了解有关绘画的更多信息。
- 我遗漏或忘记的任何其他内容都应记录在 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)
(无论你是否打算),因为它也是 public 并且由JPanel
从JComponent
继承。不要使用paint()
因为这里没有必要(也许在某些应用程序中但我从来没有需要)。将其中的所有代码移动到paintComponent
您还应该将计时器代码移到 paintComponent
之外。只需要定义一次,在后台是运行。它将继续调用您的 ActionListener class
直到您停止它。
现在,做完上面的你可能会问“为什么我画的时候只出现一个圆圈?”显而易见的答案是我只想画一个。但是为什么每次都不重复呢?
因为 super.paintComponent(g)
每次调用 paintComponent
时都会清除 JPanel
,就像它应该的那样。所以如果你想画多个圆(或其他东西),你需要把它们放在一个列表中,从paintComponent
之内画出来。由于包括绘画和计时器在内的所有事件都是 运行 在单个线程(事件调度线程)上串联的,因此将处理保持在最低限度很重要。因此,如果可能,大多数计算应该在该线程之外完成。 EDT processing should be as simple and as quick as possible.
我的第一个答案是一个圆围绕一个点。但也许那不是你想要的。您可能只想将圆从固定距离均匀地围绕中心放置。我提供了两种方法。
- 像以前一样使用旋转。 Imo,这是最简单的。角度是固定的,每次旋转被调用时,它是累加的。所以只需调用该方法
nCircle
次并绘制圆圈。并记住计算x and y
坐标以校正半径。 - 使用三角函数计算圆圈的位置。这使用基于
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();
}
}