1

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.

Nicholas Eason
  • 290
  • 4
  • 13
  • For reference, here's a working [example](http://stackoverflow.com/a/3078354/230513) using `getSubimage()`. – trashgod Dec 01 '14 at 21:57
  • 1
    First mistake - `Graphics g = getGraphics();` <-- This is not how painting works in Swing, painting is controlled by the `RepaintManager` which is responsible for scheduling paint events. When required, you component's `paint` method will called and then class a chain of methods to facilitate the actual painting process. See [Performing Custom Painting](http://docs.oracle.com/javase/tutorial/uiswing/painting/) and [Painting in AWT and Swing](http://www.oracle.com/technetwork/java/painting-140037.html) for more details – MadProgrammer Dec 01 '14 at 23:51
  • 1) For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete Verifiable Example) or [SSCCE](http://www.sscce.org/) (Short, Self Contained, Correct Example). 2) One way to get images for an example, is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). – Andrew Thompson Dec 02 '14 at 00:15

1 Answers1

2

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) {

            }
        }

    }

}
Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111