绘制多个圆的问题(drawOval/Java)

绘制多个圆的问题(drawOval/Java),java,graphics,paintcomponent,Java,Graphics,Paintcomponent,我的问题如下:我的实际项目(下面的代码是的简化版本)涉及许多同心圆(每个同心圆都有不同的颜色)和使用计时器的动画。使用Draw椭圆形方法绘制圆 我的问题是,当绘制这些同心圆时,这些圆的轮廓上似乎有大量的间隙,我猜这与一个事实有关,即一个圆和任何形状一样由像素和线组成,因此圆的外观是一种错觉。我这样说是因为当我将drawOval方法替换为drawRect时,这幅画看起来就像你所期望的那样 当与其他人的代码混在一起时,我看到使用渲染提示以某种方式解决了这个问题,但却使动画速度减慢,超出了我认为可以接

我的问题如下:我的实际项目(下面的代码是的简化版本)涉及许多同心圆(每个同心圆都有不同的颜色)和使用计时器的动画。使用Draw椭圆形方法绘制圆

我的问题是,当绘制这些同心圆时,这些圆的轮廓上似乎有大量的间隙,我猜这与一个事实有关,即一个圆和任何形状一样由像素和线组成,因此圆的外观是一种错觉。我这样说是因为当我将drawOval方法替换为drawRect时,这幅画看起来就像你所期望的那样

当与其他人的代码混在一起时,我看到使用渲染提示以某种方式解决了这个问题,但却使动画速度减慢,超出了我认为可以接受的程度

下面是所画内容的屏幕截图。我们看到的不是实心不透明圆(因为在本例中绘制的所有圆都具有相同的颜色),而是:

这是我的简化代码:

Test10

import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Test10 extends JPanel {
Circle[] circles;
    public static void main(String[] args) {
        new Test10().go();
    }
    void go() {
        JFrame frame = new JFrame("Circle Test");
        frame.getContentPane().add(this);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        circles = new Circle[200];
        for (int i = 0; i < 200; i++) {
            circles[i] = new Circle(i, ((2 * ( 200 - i) + 1)));
        }
        repaint();
        frame.setPreferredSize(new Dimension(500,500));
        frame.pack();
        frame.setVisible(true);
    }
    public void paintComponent(Graphics g) {
        for (Circle circle : circles ) {
            circle.draw(g);
        }
    }
}
谁能给我解释一下a)为什么会发生这种情况,b)如何克服这个问题。


更新
尝试了各种方法,包括从最外面的圆开始,使用fillOval而不是drawOval,使用更高的笔划值,我仍然发现某些人工制品与Pavel发布的屏幕截图相似,存在问题。这是我运行动画的完整应用程序的一个屏幕截图,如果你仔细看,你可以看到大部分给定圆的颜色不一致,导致这些奇怪的结果。它们的分布实际上遵循与上面发布的屏幕截图相同的模式,因此很明显,这些选项没有解决一些基本问题。这是我的屏幕截图:

您可以尝试在Circle类的内部绘制函数中添加这条线:

Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//and draw the Oval on g2
另一种解决方案可能是填充圆圈:

Ellipse2D.Double circle = new Ellipse2D.Double(x, y, diameter, diameter);
g2.fill(circle);

你可能想做得更大一些。在类似于你的情况下,我很幸运地做到了这一点,因为计算机无法画出一个完美的圆

计算机使用正方形像素来近似真实的圆,但不可能达到完美,这会导致某些像素无法显示

画一个圆会对你有帮助


你能试一下倒圆法而不是倒圆法吗

g.fillOval(topLeft, topLeft, diameter, diameter);

画完美的圆是不可能的

尝试使用以下方法

public void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setStroke(new BasicStroke(2));
        int i = 0;
        for (Circle circle : circles ) {
            Shape circle2 = new Ellipse2D.Double(i++, i, circle.diameter, circle.diameter);
            g2d.draw(circle2);
        }
    }
你说你尝试了
渲染提示
,这减慢了你的动画速度,但你没有给我们任何动画代码,所以也许可以试试我的代码(最好看看动画实现)。看起来好多了,但仍然不是你想要的。将笔划设置为另一个值将解决此问题(至少设置为2)。另一种方法是使用
.fill()
而不是
.draw()
。我知道它并不完美,但你可以试试

另一个想法

我想,也许你可以给你的图像添加一些模糊,这样那些伪影就看不见了? 我以前没有做过,但我发现了这个():

现在,在
go()
方法中:

frame.setGlassPane(new BlurGlass(frame));
frame.getGlassPane().setVisible(true);
对我来说好多了。使用此玻璃窗格颜色玩一玩(尝试将.3f更改为其他值)


改变你的想法。从最外面的圆开始,然后画内圈,以此类推,最后画最小的圆。在此过程中,您应该使用
fillOval

对于圆/椭圆通常有用的另一个渲染提示是

g.setRenderingHint( RenderingHints.  KEY_STROKE_CONTROL,
                    RenderingHints.VALUE_STROKE_PURE);

看看我的。

画一个填充圆或两个同心填充圆不就行了吗?看看我的文章的顶部,在完整的应用程序中,每个圆都有不同的颜色,创建了一系列漂亮的同心圆。这就是我不使用Fillova的原因,不管怎样,谢谢:你是否从Futurama实现了hypnotoad?;-)我的比你的好。我在你的丝网印刷上看到的那些对称的手工艺品是不可取的。谢谢你的回答,虽然到目前为止似乎是最有用的。是的,我也得到了这些人工制品,关于如何去除它们的任何线索?谢谢稍后会有一个游戏,看起来很有希望。尝试一下,我对我的原始帖子进行了更新,以显示这会带来什么样的结果,因为它们并不理想。这种方法当然有帮助,但它仍然存在一个问题。谢谢你的帮助,如果你能看一下更新,我将不胜感激:)嗨,谢谢,我实际上已经尝试过这种方法,虽然它在小范围内工作,但当涉及到大量不同的颜色时,它会产生有趣的人工制品。我已经编辑了我的问题,将此信息与另一个屏幕截图一起包括在内。再次感谢,这是因为填充椭圆填充圆,并且圆的半径之间存在很大差异。如果你想画一个有厚边框的空圆(有一个完美的圆),那么你可以在圆角内画一个半径几乎相同的椭圆。谢谢你的回复。两个圆的半径相差很大?相邻圆的半径相差1,所以我不太明白你的意思…哦,我没听清楚。不过,试试我改进后的想法,可能会有帮助。正如我所怀疑的,非常感谢。我的问题还没有解决,我已经为我的问题添加了详细信息,如果您仍然有兴趣帮助,非常感谢该链接,稍后将有一个很好的阅读!感谢您的帮助,有关问题持续存在的原因的详细信息,请参阅更新。非常好的建议,尽管我需要熟悉渲染提示。另一种方法是预先确定一些同心圆的图像,并逐渐显示这些图像。可惜这不是一个程序化的解决方案,它可能会给你更好的图形。嗯,完整的应用程序是一个动画
frame.setGlassPane(new BlurGlass(frame));
frame.getGlassPane().setVisible(true);
g.setRenderingHint( RenderingHints.  KEY_STROKE_CONTROL,
                    RenderingHints.VALUE_STROKE_PURE);