1

我需要在表单上显示大量(500+)小圆圈来模拟 LED。但是,这些圆圈需要非常小,直径约为 8 或 9 个像素。

到目前为止,在我的测试中,我已经整理了一些代码,这些代码创建了一个使用 Shape (Ellipse2D.Double) 的 Led 类,并通过 JFrame 的 paint 方法将其直接显示在 JFrame 上。

这导致我有两个观察/问题:

1) 首先,除非有替代方法,否则 Java 在绘制小圆圈方面似乎存在问题。它们似乎在右下角以默认(或 1 个像素)的笔宽“中断”,这会将这部分切断,留下一个变形的圆圈。如果有什么方法可以画出(很多)小圆圈并让它们看起来正确吗?

2)我的子类 JFrame 覆盖了绘制这些“led”的paint方法,尽管也调用了 super.paint 以确保绘制 JFrame。但是,我看到它很少在第一次出现时绘制 LED,或者当表单移出屏幕并移回时,或者当应用程序放在前面并再次移开时,唯一一次绘制方法是当我最小化/最大化表单时调用。每次表单需要绘画时不应该调用绘画吗?

4

4 回答 4

3

你不应该覆盖paint()。请改用paintComponent()。此外,JFrame 有点奇怪,我会使用 JPanel 作为我的 BaseClass。

关于您的观察:这可能是由抗锯齿引起的吗?您是否尝试通过 setRenderingHints() 关闭抗锯齿功能?

编辑:在下面的评论之后,我写了一个小测试程序。圆圈看起来不错:

import javax.swing.*;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.Dimension;
import java.awt.RenderingHints;

class Test extends JFrame {

    public Test() {
        setContentPane(new JPanel() {
                public void paintComponent(Graphics g){
                    super.paintComponent(g);
                    Graphics2D g2d = (Graphics2D) g;
                    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                    for (int i = 0; i < 500; i++){
                        int x = (int) (Math.random() * getWidth());
                    int y = (int) (Math.random() * getHeight());
                    g.fillOval(x,y,8,8);
                    }
                }
        });
    }

    public static void main(String[] args){
        Test t = new Test();
        t.setSize(new Dimension(640, 480));
        t.setVisible(true);
    }
}
于 2010-01-04T14:22:06.570 回答
2

一段时间以来,我一直在努力解决这个问题,结果与此处描述的结果相似,当我最终得知 fillOval() 比 drawOval() 或 Ellipse2D 在实现圆度方面做得更好的事实时。以下略显老套的方法让我得到了我需要的东西:

g2d.setColor(Color.black);                    
g2d.fillOval((int)x, (int)(y - w / 2), (int)w, (int)w);
g2d.setColor(Color.white);           
g2d.fillOval((int)x+1, (int)(y - w / 2)+1, (int)w-2, (int)w-2);
于 2011-03-25T18:44:00.987 回答
1

这些 LED 应该是组件,就像表单上的其他所有东西一样。我认为你应该使用图标,也许ImageIcon是 s,来代表你的 LED。这样,您基本上可以让它们渲染一次,然后在需要时显示相同的图像。您可以使用图像很方便,因为这样您就可以使用具有您想要看到的形状的图像。

于 2010-01-04T14:22:10.587 回答
1

就“中断”而言,我会查看图形对象的斜角设置。

但是,我建议在程序启动时阅读 .png 然后显示它,而不是自己绘制。


RE:paint() 不会一直被调用。

是的,这就是它的工作原理。如果你需要在某个时间重绘你的组件,你需要强制它。调用 repaint() 强制重绘。

如果您要从另一个线程(即计时器线程)调用 repaint(),请务必将调用包装在 SwingUtilities.invokeLater() 中:

SwingUtilities.invokeLater( new Runnable()
{
    @Override
    public void run()
    {
        myForm.repaint();
    }
} );

更新:也许你应该发布一些代码......我把一个小测试应用程序放在一起,没有发现小圆圈有任何问题。

public class MyPanel extends JPanel
{
    public void paint(Graphics _g)
    {
        Graphics2D g = (Graphics2D) _g;

        g.setStroke( new BasicStroke(1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND) );
        for(int x = 10, w = 1; w < 20; x += w*2, w++)
        {
            Ellipse2D.Double ed = new Ellipse2D.Double(x, 10, w, w);
            g.fill( ed );
        }

        for(int x = 10, w = 1; w < 20; x += w*2, w++)
        {
            Ellipse2D.Double ed = new Ellipse2D.Double(x, 80, w, w);
            g.draw( ed );
        }
    }

    public static void main(String[] args)
    {
        JFrame frame = new JFrame();
        frame.add( new MyPanel() );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setSize( 400, 400 );

        frame.setVisible( true );
    }
}

我尝试改变笔画参数以查看是否会导致视觉中断,但没有成功。你看到了什么?


不要打死马,但是当我放大该程序的输出时,我的圆圈几乎是对称的,左边减去了一点像素粪便:

圆圈图片

这与您得到的相似吗?

于 2010-01-04T14:22:46.263 回答