在java中绘制图像的奇怪行为

时间:2014-03-12 05:39:16

标签: java drawimage

我通过在前者之后几十毫秒绘制不同的图像来制作动画。像这样的东西:

 drawimage(image1,0,0,null);

 try {

   Thread.sleep(100);

 }catch(Exception e){//To do something

 }

 drawimage(image2,0,0,null);

但第一张图片在第二张图片出现之前不会显示。这意味着它们同时出现。

我的问题是为什么会发生这种情况?

3 个答案:

答案 0 :(得分:1)

程序在当前状态下同时绘制两个图像,因为draw methods中有两个loop(如果你确实在使用循环)。

为了解决这个问题,您应该只使用一种绘制方法,并将延迟保留在同一位置。但是,为了遍历所有不同的图像变量(如果你在数组中将它们命名为数字1,2,3,4 ...等),你可以使用for循环来绘制它们:

for (int i = 0; i<  *however many images you have*; i++){
     drawimage(image[i],0,0,null);

     try {

       Thread.sleep(100);

     }catch(Exception e){//To do something

     }
}

修改

您不会在paintComponent内使用延迟。既然你是,那就是可能导致问题的原因。将延迟移到程序的main方法中。

答案 1 :(得分:1)

  

我:这段代码到底在哪里?它是在paint / paintComponent方法中吗?

     

OP:它位于paintComponent中。我用它来制作动画,但我不确定这是一个好方法。

你是对的,这不是一个好方法。 不要Thread.sleep方法中调用paintComponent。我会一起避免使用Thread.sleep并使用javax.swing.Timer。查看更多How to Use Swing Timers

查看示例herehere以及herehere

你可以......

使用list ImagesTimer事件的每次迭代触发,将另一个Image添加到List<Image>并致电repaint()

你可以......

拥有MyImage对象类,其中包含Image字段和boolean draw字段。在Timer中,循环遍历MyImage对象并执行类似

的操作
    for (MyImage image: images) {
        if (!image.isDraw()) {
            image.setDraw(true);
            break;
        }
    }
    repaint();

MyImage List只需在paintComponent方法中循环显示它们,并将其称为drawImage方法即可。


运行此exmaple,显示第一个选项

enter image description here

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class AnimateImages extends JPanel {
    private static final int IMAGE_ROWS = 10;
    private static final int IMAGE_COLS = 10;
    private static final int IMAGE_SIZE = 50;
    private static final int DIM_WIDTH = IMAGE_COLS * IMAGE_SIZE;

    private final List<MyImage> images;
    private Image image;
    private int currX = -IMAGE_SIZE;
    private int currY;

    public AnimateImages() {
        try {
            image = ImageIO.read(new URL("http://swoo.co.uk/content/images/icons/stackoverflow.png"));
        } catch (IOException ex) {
            Logger.getLogger(AnimateImages.class.getName()).log(Level.SEVERE, null, ex);
        }
        images = createImages();

        Timer timer = new Timer(100, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                for (MyImage image : images) {
                    if (!image.isDraw()) {
                        image.setDraw(true);
                        break;
                    }
                    repaint();
                }
            }
        });
        timer.start();
    }

    private List<MyImage> createImages() {
        List<MyImage> list = new ArrayList<>();
        for (int i = 0; i < IMAGE_ROWS * IMAGE_COLS; i++) {
            if (currX >= DIM_WIDTH) {
                currX = 0;
                currY += IMAGE_SIZE;
            } else {
                currX += IMAGE_SIZE;
            }
            list.add(new MyImage(image, currX, currY));

        }
        return list;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (MyImage img : images) {
            img.draw(g);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(IMAGE_SIZE * IMAGE_COLS, IMAGE_SIZE * IMAGE_ROWS);        
    }

    public class MyImage {

        Image image;
        int x, y;
        boolean draw = false;

        public MyImage(Image image, int x, int y) {
            this.image = image;
            this.x = x;
            this.y = y;
        }

        public void setDraw(boolean draw) {
            this.draw = draw;
        }

        public boolean isDraw() {
            return draw;
        }

        public void draw(Graphics g) {
            if (draw) {
                g.drawImage(image, x, y, IMAGE_SIZE, IMAGE_SIZE, AnimateImages.this);
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new AnimateImages());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

答案 2 :(得分:0)

您的回答

您收到此结果是因为它正在打印image1,等待.1秒然后再打印image2。然后它不会等待,游戏立即更新,然后打印image1image2的展示时间是微观的,您可能只会看到image1

此外,图像永远不会被删除或替换,因此您不断地在彼此之上绘制图像,这会导致内存泄漏,并且可能是您看到两个图像的原因。

<强>考虑

这是我从this tutorial获得并仍然使用的一个方便的小动画类。这个类非常方便,你可以添加每个动画所需的动画精灵。

使用此课程,当您执行drawImage()时,可以使用object.getImage()提取动画的当前帧。

确保您在游戏的主循环中调用动画的update()方法,以便不断更新动画。

import java.awt.Image;
import java.util.ArrayList;

public class Animation {

    private ArrayList frames;
    private int currentFrame;
    private long animTime;
    private long totalDuration;

    public Animation() {
        frames = new ArrayList();
        totalDuration = 0;

        synchronized (this) {
            animTime = 0;
            currentFrame = 0;
        }
    }

    public synchronized void addFrame(Image image, long duration) {
        totalDuration += duration;
        frames.add(new AnimFrame(image, totalDuration));
    }

    public synchronized void update(long elapsedTime) {
        if (frames.size() > 1) {
            animTime += elapsedTime;
            if (animTime >= totalDuration) {
                animTime = animTime % totalDuration;
                currentFrame = 0;
            }
            while (animTime > getFrame(currentFrame).endTime) {
                currentFrame++;
            }
        }
    }

    public synchronized Image getImage() {
        if (frames.size() == 0) {
            return null;
        } else {
            return getFrame(currentFrame).image;
        }
    }

    private AnimFrame getFrame(int i) {
        return (AnimFrame) frames.get(i);
    }

    private class AnimFrame {

        Image image;
        long endTime;

        public AnimFrame(Image image, long endTime) {
            this.image = image;
            this.endTime = endTime;
        }
    }

}