用 "trail" 画一个平滑的圆

Drawing a smooth circle with "trail"

我可以使用 Graphics2D 制作一个没有 "wobbly" 效果的平滑圆圈吗?如果是,如何?要理解我的意思,您必须 运行 以下示例:

import java.awt.Color;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.*;

public class CircleExample {

    static int angle = 0;

    public static void main(String[] args) {

        JFrame frame = new JFrame();

        new Thread(new Runnable() {
            public void run() {
                while (true) {

                    if (angle >= 360) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        angle = 0;
                    }

                    angle++;

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    frame.repaint();
                }
            }

        }).start();

        frame.getContentPane().add(new Circle());
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(200, 200);
        frame.setVisible(true);

    }

    static class Circle extends JPanel {

        @Override
        public void paintComponent(Graphics g) {

            super.paintComponent(g);

            Graphics2D gg = (Graphics2D) g;

            gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);

            gg.setColor(Color.BLACK);

            gg.drawArc(40, 40, 100, 100, 0, angle);

        }

    }

}

抖动效果是由于不同弧的抗锯齿决策略有不同造成的,可能是由于舍入误差。

解决此问题的一种方法是绘制一个完整的圆圈——它始终以相同的方式抗锯齿呈现——但将其剪裁到给定的圆弧。所以只有一部分会被实际绘制出来。

以下内容基于 Andrew Thompson 基于计时器的回答(已被删除),但我为每个原始线程添加了一些延迟,并使 angle 成为 Circle class 而不是静态变量。

public static void main(String[] args) {
    final JFrame frame = new JFrame();

    frame.getContentPane().add(new Circle());
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.setSize(200, 200);
    frame.setVisible(true);
}

static class Circle extends JPanel {

    private int angle = 0;
    // The clip arc is going to be slightly larger than the actual
    // arc, otherwise some antialiasing pixels will be clipped off.
    private Arc2D clip = new Arc2D.Double(35,35,110,110,0,360,Arc2D.PIE);

    Circle() {

        ActionListener actionListener = new ActionListener() {

            int waitCounter = 0;

            @Override
            public void actionPerformed(ActionEvent e) {
                // When the angle reaches 360, set a wait for 100
                // runs of the timer.
                if (angle >= 360) {
                    angle = 0;
                    waitCounter = 100;
                }
                // If waiting, count down the time. When the wait
                // counter is zero, do the actual work.
                if (waitCounter > 0) {
                    waitCounter--;
                } else {
                    angle++;
                    repaint();
                }
            }
        };

        // The timer itself runs every 10 milliseconds.
        Timer timer = new Timer(10, actionListener);
        timer.start();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D gg = (Graphics2D) g;
        gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);

        // Set the clipping arc to the current angle.
        clip.setAngleExtent(angle);
        gg.setClip(clip);

        // Draw a full circle. It will be clipped to the arc set above.
        gg.setColor(Color.BLACK);
        gg.drawOval(40,40,100,100);
    }
}