前段时间研究了一下3d游戏的制作,由于是0基础,我就把游戏引擎方面的介绍看了一遍。之后发现做3d游戏要用到骨骼动画,骨骼动画又要用到模型,模型自然是可以在网上下载,但是我是个很不知足的人,因此又钻到3dmax里面学习如何展UV,绑定模型到骨骼,为骨骼添加蒙皮,学的不是很顺利。因此在我用网上下下来的动作库弄出一个能动的模型出来的时候,很兴奋!于是我想把我的成果分享给我的好朋友,但是他用的是mac的机器!mac机器就是奇怪,装不了暴风影音之类的.exe格式的文件!我一想java是跨平台的,而且mac本子现阶段自身也集成了jdk,于是就想自己写一个程序来播放我截下来的截图。
我截图用的是jdk中的robot类,用起来很方便,我改了一下网上找到的小程序,让他能够自动截屏并保存图片到指定的位置。我搞了一个线程来截整张桌面图,每50ms截一张,走到这一步倒是没有遇到什么大的问题。关键是截下来播放连续截图的问题(我截下来的图片是按数字递增的方式来命名的),我又搞了一个JFrame,里面放了一个JPanel,在paint()方法里面每画一次就画出截图的下一张图片,然后另起一个线程来不停地repaint().好,走到这里问题就来了!我用了两种方法:第一种是在画图片之前就把所有的截图都加载到内存中去,用的是以下的代码
Java code
private static Toolkit tk = Toolkit.getDefaultToolkit();
    private Image[] videoImages = new Image[COUNT];
    // 不预先就加载好的话,到时候卡的很!
    public void iniPictures() {
        for(int i = 0; i < COUNT; i ++) {
            videoImages[i] = tk.getImage(Player2.class.getClassLoader()
                    .getResource("jpgImages/Test" + (i + 1) + ".JPG"));
        }
    }这种方法的话,竟然爆出这样的错误,我实在是不能理解
Exception in thread "Image Fetcher 0" java.lang.OutOfMemoryError: Java heap space
顺便说一下我电脑的配置:2.6g双核AMD CPU,2G内存还有一种方法就是每画一张的时候就用ImageIO读一次图片,我的想法是,这样肯定不够快,因为既要加载,又要画,每50ms花一帧的话肯定显得有点卡!不过出乎我意料的是,无论用的是上述哪一种方法,播放连续截图的时候都是卡的我眼泪直流,而且JFrame窗体老变白,我在画图片之前又将背景绘制成全黑,还是一样,还有会出现白背景!另外就是,我在将播放的帧数设置为每秒20帧的时候(也就是每50ms画一帧),根本就看不到图片出现;将其改为150ms的时候,也能看到图片的模糊影像,设置为两百的时候,才会出现上上面说的那种很卡的播放效果--我就疑惑了,难道每50ms画一张图都不行(说明:无论是用第一种方法,还是第二种方法,都是类似的效果,当然,如果是第一种方法的话,肯定是在还没报错之前的效果,事实是第一种方法才放个10几帧就报错了)?不知道我的问题有没有描述的清楚,下面我会贴出我的代码。请高人或有过类似经历的人予以指点,不甚感激!

解决方案 »

  1.   

    一次加载很多图片并且图片又很大的话,内存溢出很正常,因为JVM默认的内存不是很高,你可以用-Xmx500m把内存设大一点。我做图片切割的时候也出现这种问题(一张图片就17MB);画图片可以采用双缓冲机制,具体得看你的代码,是不是什么地方程序写的有问题?
      

  2.   

    还有就是画图别再paint()里面画,而应该在paintComponent()里面
      

  3.   

    package code.play;import java.awt.Color;
    import java.awt.Frame;
    import java.awt.Graphics;
    import java.awt.Image;
    import java.awt.Panel;
    import java.awt.Toolkit;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;public class Player2 extends Frame {
        private static final long serialVersionUID = 8055029906280922502L;
        private static Toolkit tk = Toolkit.getDefaultToolkit();
        
        // 从1到270共270张图片
        private static final int COUNT = 270;
        private Image[] videoImages = new Image[COUNT];
        
        public Player2() {
            this.setSize(1024, 768);
            this.setLocation(0, 0);
            this.addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent e) {
                    System.exit(1);
                }
            });
            this.iniPictures();
            ContentPane cp = new ContentPane();
            this.add(cp);
            new Thread(cp).start();
            this.setVisible(true);
        }
        
        // 不预先就加载好的话,到时候卡的很!
        public void iniPictures() {
            for(int i = 0; i < COUNT; i ++) {
                videoImages[i] = tk.getImage(Player2.class.getClassLoader()
                        .getResource("jpgImages/Test" + (i + 1) + ".JPG"));
            }
        }    public static void main(String[] args) {
            new Player2();
        }
        
        class ContentPane extends Panel implements Runnable {
            private static final long serialVersionUID = -5543236608700268480L;
            private int picNumber = 0;
            
            public ContentPane() {
                this.setSize(1024, 768);
                this.setVisible(true);
            }        public void paint(Graphics g) {
                if(picNumber < COUNT) {
                    System.out.println("images/Test" + (picNumber + 1) + ".JPG");
    //                Color c = g.getColor();
    //                g.setColor(Color.BLACK);
    //                g.fillRect(0, 0, 1024, 768);
    //                g.setColor(c);
                    g.drawImage(videoImages[picNumber], 0, 0, this);
                }
            }
            
            public void run() {
                while(picNumber < COUNT) {
                    this.repaint();
                    picNumber ++;
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    //                if(picNumber == 10) {
    //                    picNumber = 0;
    //                }
                }
                System.exit(0);
            }
        }
        
    //    class T extends Thread {
    //        private ContentPane cp;
    //        private int times = 0;
    //        public T(ContentPane cp) {
    //            this.cp = cp;
    //        }
    //        
    //        public void run() {
    //            while(times < 270) {
    //                this.cp.repaint();
    //                this.times ++;
    //                System.out.println("第多少次了:" + times);
    //                try {
    //                    Thread.sleep(50);
    //                } catch (InterruptedException e) {
    //                    e.printStackTrace();
    //                }
    //            }
    //        }
    //    }
    }
      

  4.   

    楼上的方便给一个具体的demo么?我学java也不是很久,对细节不是很清晰,拜谢!
      

  5.   

    下面是刚写的一个用来播放图片的JPanel,测试过了,没问题。我也是一次都加载到内存,图片很多很大时可能增加内存,要不会内存溢出。界面部分用Netbeans做的,若果需要,可邮件电我。package com.monitor.imagetest;import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.image.BufferedImage;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.JPanel;/**
     *
     * 循环播放图片
     *
     * @author monitor
     * Created on 2010-12-22, 16:38:02
     */
    public class DisplayJPanel extends JPanel implements Runnable{
        /** 背景颜色 */
        private final Color B_COLOR=Color.LIGHT_GRAY;
        /** 起始X坐标 */
        private final int WORK_X=10;
        /** 起始Y坐标 */
        private final int WORK_Y=10;
        /** 要播放的图片 */
        private List<BufferedImage> imageList=new ArrayList<BufferedImage>();
        /** 当前要画的图片 */
        private BufferedImage currentImage=null;
        /** 播放延时 */
        private int delay=50;
        /** 是否播放 */
        private boolean work=true;
        /** 是否暂停 */
        private boolean stop=false;    public DisplayJPanel(){
        }    public DisplayJPanel(List<BufferedImage> imageList){
            this.imageList=imageList;
        }    public void run(){
            while(work){
                if(stop || imageList==null || imageList.isEmpty()){
                    sleep(1000);
                    continue;
                }
                for(BufferedImage image:imageList){
                    currentImage=image;
                    repaint();
                    sleep(delay);
                }
            }
        }    @Override
        public void paintComponent(Graphics g){
            g.setColor(B_COLOR);
            g.fillRect(0, 0,this.getWidth(),this.getHeight());
            if(currentImage!=null){
                g.drawImage(currentImage,WORK_X,WORK_Y,null);
            }
        }    private void sleep(int s){
            try{
                Thread.sleep(s);
            }catch(Exception e){
            }
        }    public void setDelay(int delay) {
            this.delay = delay;
        }    public void setImageList(List<BufferedImage> imageList) {
            this.imageList = imageList;
        }    public void setWork(boolean work) {
            this.work = work;
        }    public void setStop(boolean stop) {
            this.stop = stop;
        }
    }