简体   繁体   中英

drawImage error when trying to draw a sprite onto a JFrame

I have this really crappy sprite sheet that I made, which is basically just a bunch of circles and ovals so I can grasp Sprite animation.

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;

public class CircleSprite extends JFrame implements ActionListener, Runnable{

BufferedImage circles;
BufferedImage[] test;
Timer timer;
int cycle = 0;
Graphics g = getGraphics();
public void asd(){
    setSize(500,500);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    try {
        circles = ImageIO.read(new File("CircleTest.png"));
    } catch (IOException e) {
        e.printStackTrace();
    }

    final int width = 206;
    final int height = 206;
    final int rows=  2;
    final int columns = 3;

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    test = new BufferedImage[rows * columns];
    try{
        for(int i = 0; i < rows; i++)
            for(int j = 0;j<columns;j++)
                {
                    test[i*columns + j] = circles.getSubimage(j * width, i * height, width, height);
                }
    }catch(Exception e){
        e.printStackTrace();
    }

    timer = new Timer(500, this);

    setVisible(true);

}

public void actionPerformed(ActionEvent e){
    //0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0, 1, 2, etc.
    repaint();

    g.drawImage(test[cycle], 25, 25, null);


    if(cycle >= 5){
        cycle--;
    }
    if(cycle <=0){
        cycle++;
    }

}

public void run(){
    asd();

    while(timer.isRunning() == false && this.isVisible() == true){
        timer.start();
        try {
            CircleSpriteRun.t1.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

}

The error occurs here: g.drawImage(test[cycle], 25, 25, null);

At first I though it had to do with the ImageObserver being null, and looking further into it, I was wrong. Now, I think it might be because of the timer, but I don't really know too much about Timers, let alone the swing one.

This all runs on a Thread being executed in another class, and it could also have to do with the while statement in the run method, since that also involves the timer.

Since you didn't provide a runnable example, I created one to show how to properly code a Swing application.

First, you must start a Swing application with the SwingUtilities.invokeLater method. Here's how I started the CircleSprite class.

public static void main(String[] args) {
    SwingUtilities.invokeLater(new CircleSprite());
}

Second, you should use a JPanel for drawing, not a JFrame. Here's the DrawingPanel I created. My version of CircleSprite draws a circle in a random location every 2 seconds.

public class DrawingPanel extends JPanel {

    private static final long serialVersionUID = -4603711384104715819L;

    private int x;
    private int y;

    private BufferedImage image;

    public DrawingPanel(BufferedImage image) {
        this.image = image;
        this.x = 0;
        this.y = 0;
        setPreferredSize(new Dimension(500, 500));
    }

    public void setPoint(int x, int y) {
        this.x = x;
        this.y = y;
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, x, y, null);
    }

}

Third, you create the Swing GUI before you do anything with the Swing GUI. Here's the run method from the CircleSprite class. I create the GUI, then I start the thread that does the random drawing.

public void run() {
    circle = createCircle();

    frame = new JFrame("Circle Sprite");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    drawingPanel = new DrawingPanel(circle);
    frame.add(drawingPanel);

    frame.pack();
    frame.setLocationByPlatform(true);
    frame.setVisible(true);

    new Thread(new RandomDraw(drawingPanel)).start();
}

Fourth, you only extend a Swing component when you want to override a method, like I did in the DraawingPanel class. You use Swing Components otherwise.

Here's the entire, runnable, CircleSprite class. You can use this as a model for future Swing applications.

package com.ggl.testing;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class CircleSprite implements Runnable {

    private BufferedImage circle;

    private DrawingPanel drawingPanel;

    private JFrame frame;

    @Override
    public void run() {
        circle = createCircle();

        frame = new JFrame("Circle Sprite");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        drawingPanel = new DrawingPanel(circle);
        frame.add(drawingPanel);

        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);

        new Thread(new RandomDraw(drawingPanel)).start();
    }

    private BufferedImage createCircle() {
        BufferedImage image = new BufferedImage(100, 100, 
            BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();

        g.setColor(Color.WHITE);
        g.fillRect(0, 0, 100, 100);
        g.setColor(Color.BLUE);
        g.fillOval(10, 10, 80, 80);
        g.dispose();

        return image;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new CircleSprite());
    }

    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = -4603711384104715819L;

        private int x;
        private int y;

        private BufferedImage image;

        public DrawingPanel(BufferedImage image) {
            this.image = image;
            this.x = 0;
            this.y = 0;
            setPreferredSize(new Dimension(500, 500));
        }

        public void setPoint(int x, int y) {
            this.x = x;
            this.y = y;
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(image, x, y, null);
        }

    }

    public class RandomDraw implements Runnable {

        private DrawingPanel drawingPanel;

        private Random random;

        public RandomDraw(DrawingPanel drawingPanel) {
            this.drawingPanel = drawingPanel;
            this.random = new Random();
        }

        @Override
        public void run() {
            while (true) {
                sleep();
                int x = random.nextInt(400);
                int y = random.nextInt(400);
                drawingPanel.setPoint(x, y);
            }
        }

        private void sleep() {
            try {
                Thread.sleep(2000L);
            } catch (InterruptedException e) {

            }
        }

    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM