用时间延迟绘制图像



我想在一段时间延迟后在生成的坐标上绘制图像,但是我得到了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);
    }
}

不要使用线程进行动画。相反,您应该使用摆动计时器。然后,当计时器启动时,您要调整要移动并在组件上调用repaint()的图像的属性(x1/y1,x2,y2)。这些属性应该是类的属性。

不要使用getGraphics()。自定义绘画是通过覆盖paintComponent()方法来完成的,然后使用传递给自定义绘画方法的图形对象。因此,基本上,我认为,您的paintComponent()方法应调用您的drawLine(...)方法。

似乎是您的getGraphics()调用返回null。您应该ovverride the PaintComponent()方法,而不是调用getGraphics(),然后使用Repaver()。

更新

getGraphics()的文档说

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

您的班级无法显示,因为您在构造函数中不致电super()。扩展课程时,请始终致电父类的构造函数。

注意:文档的这个特定部分并不容易找到。当您查看一种方法并说它覆盖了父类方法时,请始终查看父类的方法,因为通常(阅读:大部分时间)被覆盖的方法会呼叫父母的方法。挖掘文档通常会给您一个答案,以解决为什么您的程序不起作用,尽管不要忘记也不时仔细检查自己的代码。

最新更新