发布我的方法让 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.sinMath.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 并且由 JPanelJComponent 继承。不要使用 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();
    }
}