如何将BufferedImage绘制到JPanel [英] How to Draw an BufferedImage to a JPanel

查看:97
本文介绍了如何将BufferedImage绘制到JPanel的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用某种绘制方法将精灵图像绘制到我的JPanel子类名为AnimationPanel。我创建了一个Spritesheet类,它可以生成一个包含工作表中所有精灵的BufferedImage []。在我的AnimationPanel类中,它实现了Runnable,我从AnimationPanel构造函数中实例化的spritesheet中获取BufferedImage []。我希望能够循环遍历此数组并将每个精灵显示到屏幕上。我该怎么办?这是我的AnimationPanel和Spritesheet类。



AnimationPanel



  package com.kahl.animation; 

import javax.swing.JPanel;

公共类AnimationPanel扩展JPanel实现Runnable {

//实例变量
私人Spritesheet表;
private int currentFrame;
private Thread animationThread;
private BufferedImage图片;

public AnimationPanel(Spritesheet aSheet){
super();
sheet = aSheet;
setPreferredSize(new Dimension(128,128));
setFocusable(true);
requestFocus();

}

public void run(){
BufferedImage [] frames = sheet.getAllSprites();
currentFrame = 0;
while(true){
frames [currentFrame] .draw(); //这里仍然需要一些实现
currentFrame ++;
if(currentFrame> = frames.length){
currentFrame = 0;
}
}
}

public void addNotify(){
super.addNotify();
if(animationThread == null){
animationThread = new Thread(this);
animationThread.start();
}
}

}



Spritesheet



  package com.kahl.animation; 

import java.awt.image.BufferedImage;
import java.imageio.ImageIO;
import java.io.IOException;
import java.io.File;

公共类Spritesheet {

//实例变量
private String path;
private int frameWidth;
private int frameHeight;
private int framesPerRow;
private int frames;
private BufferedImage sheet = null;

//构造函数
public Spritesheet(String aPath,int width,int height,int fpr,int numOfFrames){

path = aPath;
frameWidth = width;
frameHeight = height;
framesPerRow = fpr;
frames = numOfFrames;

try {
sheet = ImageIO.read(getClass()。getResourceAsStream());
} catch(IOException e){
e.printStackTrace();
}

}

//方法

public int getHeight(){
return frameWidth;
}

public int getWidth(){
return frameWidth;
}

public int getFramesPerRow(){
return framesPerRow;
}

private BufferedImage getSprite(int x,int y,int h,int w){
BufferedImage sprite = sheet.getSubimage(x,y,h,w);
}

public BufferedImage [] getAllSprites(){
BufferedImage [] sprites = new BufferedImage [frames];
int y = 0;
for(int i = 0; i< frames; i ++){
x = i * frameWidth;
currentSprite = sheet.getSprite(x,y,frameHeight,frameWidth);
sprites.add(currentSprite);
}
返回精灵;

}

}


解决方案


  1. 我鼓励使用 javax.swing.Timer 来控制帧速率,而不是不受控制的循环

  2. 一旦计时器滴答,你需要递增当前帧,获取当前渲染的图像并调用重绘 JPanel

  3. 使用 Graphics#drawImage 来渲染图像。

参见...





了解更多详情



您的 Spritesheet 类存在一系列级联问题,除了它实际上不会编译之外,从某些方法返回错误的值存在问题,依赖于更好计算的值......



我不得不修改你的代码,我记不起大部分了

  public int getHeight(){
return frameWidth;
}

  public BufferedImage [] getAllSprites(){
BufferedImage [] sprites = new BufferedImage [frames];
int y = 0;
for(int i = 0; i< frames; i ++){
x = i * frameWidth;
currentSprite = sheet.getSprite(x,y,frameHeight,frameWidth);
sprites.add(currentSprite);
}
返回精灵;

}

作为两个主要例子脱颖而出......



  import java.awt.Dimension; 
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

公共类TestSpriteSheet {

public static void main(String [] args){
new TestSpriteSheet();
}

public TestSpriteSheet(){
EventQueue.invokeLater(new Runnable(){
@Override
public void run(){
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch(ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}

JFrame frame = new JFrame(Testing);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

公共类TestPane扩展JPanel {

私有Spritesheet spritesheet;
private BufferedImage currentFrame;
private int frame;

public TestPane(){
spritesheet = new Spritesheet(/ Sheet02.gif,240,220);
计时器计时器=新计时器(100,新ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
currentFrame = spritesheet.getSprite(frame%spritesheet.getFrameCount ());
repaint();
frame ++;
}
});
timer.start();
}

@Override
public Dimension getPreferredSize(){
return new Dimension(240,220);
}

@Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
if(currentFrame!= null){
Graphics2D g2d =(Graphics2D)g.create();
int x =(getWidth() - currentFrame.getWidth())/ 2;
int y =(getHeight() - currentFrame.getHeight())/ 2;
g2d.drawImage(currentFrame,x,y,this);
g2d.dispose();
}
}

}

公共类Spritesheet {

//实例变量
私有字符串路径;
private int frameWidth;
private int frameHeight;
private BufferedImage sheet = null;
private BufferedImage [] frameImages;

//构造函数
public Spritesheet(String aPath,int width,int height){

path = aPath;
frameWidth = width;
frameHeight = height;

try {
sheet = ImageIO.read(getClass()。getResourceAsStream(path));
frameImages = getAllSprites();
} catch(IOException e){
e.printStackTrace();
}

}

public BufferedImage getSprite(int frame){
return frameImages [frame];
}

//方法
public int getHeight(){
return frameHeight;
}

public int getWidth(){
return frameWidth;
}

public int getColumnCount(){
return sheet.getWidth()/ getWidth();
}

public int getRowCount(){
return sheet.getHeight()/ getHeight();
}

public int getFrameCount(){
int cols = getColumnCount();
int rows = getRowCount();
返回cols *行;
}

private BufferedImage getSprite(int x,int y,int h,int w){
BufferedImage sprite = sheet.getSubimage(x,y,h,w);
返回精灵;
}

public BufferedImage [] getAllSprites(){
int cols = getColumnCount();
int rows = getRowCount();
int frameCount = getFrameCount();
BufferedImage [] sprites = new BufferedImage [frameCount];
int index = 0;
System.out.println(cols =+ cols);
System.out.println(rows =+ rows);
System.out.println(frameCount =+ frameCount);
for(int row = 0; row< getRowCount(); row ++){
for(int col = 0; col< getColumnCount(); col ++){
int x = col * getWidth();
int y = row * getHeight();
System.out.println(index ++ x +x+ y);
BufferedImage currentSprite = getSprite(x,y,getWidth(),getHeight());
sprites [index] = currentSprite;
index ++;
}
}
返回sprite;

}

}
}



<请记住,动画是随时间变化的幻觉。你需要在动画的每一帧之间提供一段延迟,让用户能够识别它,但又要足够短以使动画看起来流畅。



在上面例如,我使用 100 毫秒,只是作为一个任意值。可以使用更像 1000 / spritesheet.getFrameCount()的内容,这将允许整个动画的整秒(一秒内的所有帧)。 / p>

根据您的需要,您可能需要使用不同的值,更长或更短的动画


I am trying to use some sort of draw method to draw a sprite image to my subclass of JPanel called AnimationPanel. I have created a Spritesheet class which can generate a BufferedImage[] that contains all of the sprites in the sheet. In my AnimationPanel class, which implements Runnable, I am getting that BufferedImage[] from the spritesheet instantiated in the AnimationPanel constructor. I want to be able to loop through this array and display each sprite to the screen. How would I do this? Here are my AnimationPanel and Spritesheet classes.

AnimationPanel

package com.kahl.animation;

import javax.swing.JPanel;

public class AnimationPanel extends JPanel implements Runnable {

//Instance Variables
private Spritesheet sheet;
private int currentFrame;
private Thread animationThread;
private BufferedImage image;

public AnimationPanel(Spritesheet aSheet) {
    super();
    sheet = aSheet;
    setPreferredSize(new Dimension(128,128));
    setFocusable(true);
    requestFocus();

}

public void run() {
    BufferedImage[] frames = sheet.getAllSprites();
    currentFrame = 0;
    while (true) {
        frames[currentFrame].draw(); //some implementation still necessary here
        currentFrame++;
        if (currentFrame >= frames.length) {
            currentFrame = 0;
        }
    }
}

public void addNotify() {
    super.addNotify();
    if (animationThread == null) {
        animationThread = new Thread(this);
        animationThread.start();
    }
}

}

Spritesheet

package com.kahl.animation;

import java.awt.image.BufferedImage;
import java.imageio.ImageIO;
import java.io.IOException;
import java.io.File;

public class Spritesheet {

//Instance Variables
private String path;
private int frameWidth;
private int frameHeight;
private int framesPerRow;
private int frames;
private BufferedImage sheet = null;

//Constructors
public Spritesheet(String aPath,int width,int height,int fpr, int numOfFrames) {

    path = aPath;
    frameWidth = width;
    frameHeight = height;
    framesPerRow = fpr;
    frames = numOfFrames;

    try {
        sheet = ImageIO.read(getClass().getResourceAsStream());
    } catch (IOException e) {
        e.printStackTrace();
    }

}

//Methods

public int getHeight() {
    return frameWidth;
}

public int getWidth() {
    return frameWidth;
}

public int getFramesPerRow() {
    return framesPerRow;
}

private BufferedImage getSprite(int x, int y, int h, int w) {
    BufferedImage sprite = sheet.getSubimage(x,y,h,w);
}

public BufferedImage[] getAllSprites() {
    BufferedImage[] sprites = new BufferedImage[frames];
    int y = 0;
    for (int i = 0; i < frames; i++) {
        x = i * frameWidth;
        currentSprite = sheet.getSprite(x,y,frameHeight,frameWidth);
        sprites.add(currentSprite);
    }
    return sprites;

}

}

解决方案

  1. I'd encourage the use of a javax.swing.Timer to control the frame rate, rather than an uncontrolled loop
  2. Once the timer "ticks", you need to increment the current frame, get the current image to be rendered and call repaint on the JPanel
  3. Use Graphics#drawImage to render the image.

See...

for more details

There is a cascading series of issues with your Spritesheet class, apart from the fact that it won't actually compile, there are issues with you returning the wrong values from some methods and relying on values which are better calculated...

I had to modify your code so much, I can't remember most of them

public int getHeight() {
    return frameWidth;
}

and

public BufferedImage[] getAllSprites() {
    BufferedImage[] sprites = new BufferedImage[frames];
    int y = 0;
    for (int i = 0; i < frames; i++) {
        x = i * frameWidth;
        currentSprite = sheet.getSprite(x,y,frameHeight,frameWidth);
        sprites.add(currentSprite);
    }
    return sprites;

}

Stand out as two main examples...

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestSpriteSheet {

    public static void main(String[] args) {
        new TestSpriteSheet();
    }

    public TestSpriteSheet() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Spritesheet spritesheet;
        private BufferedImage currentFrame;
        private int frame;

        public TestPane() {
            spritesheet = new Spritesheet("/Sheet02.gif", 240, 220);
            Timer timer = new Timer(100, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    currentFrame = spritesheet.getSprite(frame % spritesheet.getFrameCount());
                    repaint();
                    frame++;
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(240, 220);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (currentFrame != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                int x = (getWidth() - currentFrame.getWidth()) / 2;
                int y = (getHeight() - currentFrame.getHeight()) / 2;
                g2d.drawImage(currentFrame, x, y, this);
                g2d.dispose();
            }
        }

    }

    public class Spritesheet {

//Instance Variables
        private String path;
        private int frameWidth;
        private int frameHeight;
        private BufferedImage sheet = null;
        private BufferedImage[] frameImages;

//Constructors
        public Spritesheet(String aPath, int width, int height) {

            path = aPath;
            frameWidth = width;
            frameHeight = height;

            try {
                sheet = ImageIO.read(getClass().getResourceAsStream(path));
                frameImages = getAllSprites();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        public BufferedImage getSprite(int frame) {
            return frameImages[frame];
        }

//Methods
        public int getHeight() {
            return frameHeight;
        }

        public int getWidth() {
            return frameWidth;
        }

        public int getColumnCount() {
            return sheet.getWidth() / getWidth();
        }

        public int getRowCount() {
            return sheet.getHeight() / getHeight();
        }

        public int getFrameCount() {
            int cols = getColumnCount();
            int rows = getRowCount();
            return cols * rows;
        }

        private BufferedImage getSprite(int x, int y, int h, int w) {
            BufferedImage sprite = sheet.getSubimage(x, y, h, w);
            return sprite;
        }

        public BufferedImage[] getAllSprites() {
            int cols = getColumnCount();
            int rows = getRowCount();
            int frameCount =  getFrameCount();
            BufferedImage[] sprites = new BufferedImage[frameCount];
            int index = 0;
            System.out.println("cols = " + cols);
            System.out.println("rows = " + rows);
            System.out.println("frameCount = " + frameCount);
            for (int row = 0; row < getRowCount(); row++) {
                for (int col = 0; col < getColumnCount(); col++) {
                    int x = col * getWidth();
                    int y = row * getHeight();
                    System.out.println(index + " " + x + "x" + y);
                    BufferedImage currentSprite = getSprite(x, y, getWidth(), getHeight());
                    sprites[index] = currentSprite;
                    index++;
                }
            }
            return sprites;

        }

    }
}

Remember, animation is the illusion of change over time. You need to provide a delay between each frame of the animation, long enough for the user to recognise it, but short enough to make the animation look smooth.

In the above example, I've used 100 milliseconds, simply as an arbitrary value. It could be possible to use something more like 1000 / spritesheet.getFrameCount(), which will allow a full second for the entire animation (all the frames within one second).

You might need to use different values, for longer or short animations, depending on your needs

这篇关于如何将BufferedImage绘制到JPanel的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆