java - 尝试将 Sprite 绘制到 JFrame 上时发生 drawImage 错误

标签 java swing animation sprite

我制作了这个非常蹩脚的 Sprite 表,它基本上只是一堆圆形和椭圆形,所以我可以掌握 Sprite 动画。

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();
        }
    }
}

}

错误发生在这里:g.drawImage(test[cycle], 25, 25, null);

起初我认为这与 ImageObserver 为空有关,进一步研究它,我错了。现在,我认为这可能是因为计时器的原因,但我对计时器了解不多,更不用说 swing 了。

这一切都在另一个类中执行的Thread上运行,并且它也可能与run中的while语句有关方法,因为这还涉及到计时器。

最佳答案

由于您没有提供可运行的示例,因此我创建了一个示例来展示如何正确编写 Swing 应用程序代码。

首先,您必须使用 SwingUtilities.invokeLater 方法启动 Swing 应用程序。以下是我如何启动 CircleSprite 类。

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

其次,您应该使用 JPanel 进行绘图,而不是 JFrame。这是我创建的 DrawingPanel。我的 CircleSprite 版本每 2 秒在随机位置绘制一个圆圈。

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);
    }

}

第三,在使用 Swing GUI 执行任何操作之前先创建 Swing GUI。这是 CircleSprite 类的 run 方法。我创建 GUI,然后启动执行随机绘图的线程。

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();
}

第四,只有当您想要重写方法时才扩展 Swing 组件,就像我在 DrawingPanel 类中所做的那样。否则您可以使用 Swing 组件。

这是整个可运行的 CircleSprite 类。您可以将其用作 future Swing 应用程序的模型。

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

            }
        }

    }

}

关于java - 尝试将 Sprite 绘制到 JFrame 上时发生 drawImage 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27236897/

相关文章:

Java JComboBox控件滚动条位置?

ios - 如何翻转tableviewcell中的两个 View

android - ViewFlipper 3D-卡片-翻转

ios - didSelect 执行不等待 didDeSelect 动画结束

java - 有没有办法在调试时永久更改变量的值,以便在后续调用中不会覆盖它?

java - 了解Dagger 2应用架构

java - 从 Class<*> 获取对象实例(反射)

java - 如何将输入从 GUI 传递到客户端而不是服务器?

java - 如何在 Ubuntu Linux 中安装 Amazon Corretto?

java - 在 GUI 上切换 'always on top'