延时绘制图像

时间:2015-05-05 14:33:38

标签: java swing nullpointerexception

我想在一段时间延迟后在生成的坐标上绘制图像,但我得到了nullpointerexception。我试图让我的图像从一个点移动到另一个点,并且可见时间延迟。

public class PaintStations extends JPanel implements Runnable {

    private static final long serialVersionUID = 6734649580151111907L;
    private Thread thread;

    public PaintStations() {
        setSize(new Dimension(MainWindow.WIDTH, MainWindow.HEIGHT));
        setOpaque(false);
    }

    @Override
    public void paintComponent(Graphics g)  {
        super.paintComponent(g);
    }

    private void plot(Graphics g, int x, int y) {
        Graphics2D g2d = (Graphics2D) g;
        Image img = Toolkit.getDefaultToolkit().getImage("cpn.png");
        g2d.drawImage(img, x, y, this);
    }

    private void drawLine(Graphics g, int x1, int y1, int x2, int y2) {
        int d = 0;

        int dy = Math.abs(y2 - y1);
        int dx = Math.abs(x2 - x1);

        int dy2 = (dy << 1); 
        int dx2 = (dx << 1); 

        int ix = x1 < x2 ? 1 : -1; 
        int iy = y1 < y2 ? 1 : -1;

        if (dy <= dx) {
            for (;;) {
                plot(g, x1, y1);
                if (x1 == x2)
                    break;
                x1 += ix;
                d += dy2;
                if (d > dx) {
                    y1 += iy;
                    d -= dx2;
                }
            }
        } else {
            for (;;) {
                plot(g, x1, y1);
                if (y1 == y2)
                    break;
                y1 += iy;
                d += dx2;
                if (d > dy) {
                    x1 += ix;
                    d -= dy2;
                }
            }
        }
    }

    @Override
    public void run() {
        drawLine(getGraphics(), 0, 0, 10, 10);
    }

    public void start() {
        thread = new Thread(this);
        thread.start();
    }
}

以下是我得到的错误:

Exception in thread "Thread-1" java.lang.NullPointerException
    at PaintStations.plot(PaintStations.java:27)
    at PaintStations.drawLine(PaintStations.java:44)
    at PaintStations.run(PaintStations.java:71)
    at java.lang.Thread.run(Unknown Source)

我正在测试将图像放在随机坐标上,但repaint();无法正常工作。似乎paintComponent()方法在generateFuelStations()结束后触发,并且屏幕上只显示最后生成的坐标上的一个图像。

public class PaintStations extends JPanel implements Runnable {

    private static final long serialVersionUID = 6734649580151111907L;
    private ArrayList<Point> stationsLocation;
    private Shape region;
    private int x;
    private int y;
    private int stationsNumber;

    public PaintStations(Shape region, int stationsNumber) {
        setSize(new Dimension(MainWindow.WIDTH, MainWindow.HEIGHT));
        setOpaque(false);
        this.region = region;
        this.stationsNumber = stationsNumber;
    }

    @Override
    public void paintComponent(Graphics g)  {
        super.paintComponent(g);
        System.out.println("Repaint!");
        Graphics2D g2d = (Graphics2D) g;
        Image img = Toolkit.getDefaultToolkit().getImage("cpn.png");
        g2d.drawImage(img, x, y, this);
    }

    private void generateFuelStations(int stationsNumber) {
        Rectangle r = region.getBounds();
        this.stationsLocation = new ArrayList<>();

        for(int i=0; i<stationsNumber; i++) {
            Random rand = new Random();

            do {
                x = (int) (r.getX() + rand.nextInt( (int) r.getWidth() ));
                y = (int) (r.getY() + rand.nextInt( (int) r.getHeight() ));
            } while(!region.contains(x,y));
            System.out.println("X: " + x + " Y: " + y);
            stationsLocation.add(new Point(x,y));
            repaint();
        }
    }

    @Override
    public void run() {
        generateFuelStations(stationsNumber);
    }
}

3 个答案:

答案 0 :(得分:3)

不要将Thread用于动画。相反,你应该使用Swing Timer。然后,当Timer触发时,调整要移动的图像的属性(x1 / y1,x2,y2)值,并在组件上调用repaint()。这些属性应该是类的属性。

不要使用getGraphics()。通过覆盖paintComponent()方法完成自定义绘制,然后使用传递给方法的Graphics对象进行自定义绘制。基本上,我认为,您的paintComponent()方法应该调用您的drawLine(...)方法。

答案 1 :(得分:0)

似乎你的getGraphics()调用返回null。你应该ovverride paintComponent()方法而不是调用getGraphics()并使用repaint()更新。

答案 2 :(得分:0)

getGraphics()的文档说

  

为此组件创建图形上下文。如果此组件当前不可显示,则此方法将返回null。

您的课程无法显示,因为您未在构造函数中调用super()。在扩展类时,始终调用父类的构造函数。

注意:文档的这一特定部分并不容易找到。当你查看一个方法并且它说它覆盖了父类的方法时,总是要查看父类的方法,因为经常(读取:大部分时间)被覆盖的方法将调用父类的方法。通过文档挖掘通常可以帮助您解决程序无法正常工作的原因,但也不要忘记同时仔细检查自己的代码。