4

我正在整理一个幻灯片程序,该程序将测量用户在每张幻灯片上花费的时间。幻灯片展示了几种不同的魔术技巧。每个技巧显示两次。中间图像显示在重复之间。每个技巧之间都会显示过渡图像。

在第一次重复一个技巧时,JPanel 颜色在单击后在屏幕上闪烁,然后显示下一个图像。在第二次重复相同技巧时不会发生这种情况。图片可能加载时间过长。

有没有一种简单的方法来预加载图像,以便第一次没有延迟?

NOTE: Original code deleted.

编辑 1/10/2013:此代码现在适用于速度较慢的机器。垃圾神的第二个附录帮助最大。mouseClick 控制结构定期要求 SwingWorker 类加载当前技巧的 40 个或更少的图像,同时还将使用的图像设置为空。我已经将我的代码简化为只有两个 Image[] 并添加了一个 main 方法,因此它是独立的。图像仍然需要运行。现在这是非常简单的代码,如果您尝试制作包含大量图像的幻灯片,我认为这将是一个不错的起点。

注意:我想我想出了如何在仍然使用多个 Image[] 的同时正确实现 SwingWorker。垃圾神和 kleopatra 这个实现是否符合您的建议?我最终没有使用发布和处理,因为我无法弄清楚如何让它与索引数组一起正常工作,但是因为 StringWorker 不会加载数组中的所有图像(只有 40 个),并且代码每 20 个图像调用一次 StringWorker,应该有一个相当不错的缓冲区。

编辑 2013 年 1 月 10 日通过在我的 Mouse 类上扩展 MouseAdapter 来更改 MouseListener。还修复了我的paintComponent 方法以包含对super.paintComponent(g) 的调用。向我的 SwingWorker 类 ImageWorker 添加了发布/处理方法。添加了一个包装类 ArrayWrapper 以允许将 imageArray[i] 及其对应的索引 int i 与发布一起传递给进程。

package slideshow3;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.util.List;

public class SlideShow3 extends JFrame
{
    //screenImage will be replaced with each new slide
    private Image screenImage;
    private int width;
    private int height;

    //Create panel for displaying images using paintComponent()
    private SlideShow3.PaintPanel mainImagePanel;

    //Used for keybinding
    private Action escapeAction;

    //Image array variables for each trick
    private Image[] handCuffs; //h
    private Image[] cups; //c

    //Used to step through the trick arrays one image at a time
    private int h = 0;
    private int c = 0;

    //Used by timeStamp() for documenting time per slide
    private long time0 = 0;
    private long time1;

    public SlideShow3()
    {
        super();

        //Create instance of each Image array
        handCuffs = new Image[50];
        cups = new Image[176];

        //start(handCuffsString);
        start("handCuffs");

        try
        {
            screenImage = ImageIO.read(new File("images/begin1.jpg"));
        }
        catch (IOException nm) 
        {
            System.out.println("begin");
            System.out.println(nm.getMessage());
            System.exit(0);
        }

        /****************************************** 
         * Removes window framing. The next line sets fullscreen mode.
         * Once fullscreen is set width and height are determined for the window
         ******************************************/

        this.setUndecorated(true);
        GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
        width = this.getWidth();
        height = this.getHeight();

        //Mouse click binding to slide advance control structure
        addMouseListener(new Mouse());

        //Create panel so that I can use key binding which requires JComponent
        mainImagePanel = new PaintPanel();      
        add(mainImagePanel);

        /****************************************** 
         * Key Binding
         * ESC will exit the slideshow
         ******************************************/

        // Key bound AbstractAction items 
        escapeAction = new EscapeAction();

        // Gets the mainImagePanel InputMap and pairs the key to the action
        mainImagePanel.getInputMap().put(KeyStroke.getKeyStroke("ESCAPE"), "doEscapeAction");

        // This line pairs the AbstractAction enterAction to the action "doEnterAction"
        mainImagePanel.getActionMap().put("doEscapeAction", escapeAction);

        /******************************************
         * End Key Binding
         ******************************************/
    }

    public static void main(String[] args) 
    {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() 
            {
                SlideShow3 show = new SlideShow3();
                show.setVisible(true);
            }
        });
    }

    //This method executes a specific SwingWorker class to preload images
    public void start(String e) 
    {
        if(e.equals("handCuffs"))
        {
            new ImageWorker(handCuffs.length, h, e).execute();
        }
        else if(e.equals("cups"))
        {
            new ImageWorker(cups.length, c, e).execute();
        }
    }

    //Stretches and displays images in fullscreen window
    private class PaintPanel extends JPanel
    {
        @Override
        public void paintComponent(Graphics g) 
        { 
            if(screenImage != null)
            {
                super.paintComponent(g);
                g.drawImage(screenImage, 0, 0, width, height, this);
            }  
        }
    }

    /******************************************
     * The following SwingWorker class Pre-loads all necessary images.
     ******************************************/

    private class ArrayWrapper
    {
        private int i;
        private Image image;

        public ArrayWrapper(Image image, int i)
        {
            this.i = i;
            this.image = image;
        }

        public int getIndex()
        {
            return i;
        }

        public Image getImage()
        {
            return image;
        }
    }

    private class ImageWorker extends SwingWorker<Image[], ArrayWrapper>
    {
        private int currentPosition;
        private int arraySize;
        private String trickName;
        private Image[] imageArray;

        public ImageWorker(int arraySize, int currentPosition, String trick)
        {
            super();
            this.currentPosition = currentPosition;
            this.arraySize = arraySize;
            this.trickName = trick;
        }

        @Override
        public Image[] doInBackground()
        {
            imageArray = new Image[arraySize];
            for(int i = currentPosition; i < currentPosition+40 && i < arraySize; i++)
            {
                try 
                {
                    imageArray[i] = ImageIO.read(new File("images/" + trickName + (i+1) + ".jpg"));
                    ArrayWrapper wrapArray = new ArrayWrapper(imageArray[i], i);
                    publish(wrapArray);
                } 
                catch (IOException e) 
                {
                    System.out.println(trickName);
                    System.out.println(e.getMessage());
                    System.exit(0);
                }
            }
            return imageArray;
        }

        @Override
        public void process(List<ArrayWrapper> chunks)
        {
            for(ArrayWrapper element: chunks)
            {
                if(trickName.equals("handCuffs"))
                {
                    handCuffs[element.getIndex()] = element.getImage();
                }
                else if(trickName.equals("cups"))
                {
                    cups[element.getIndex()] = element.getImage();
                }
            }
        }

        @Override
        public void done()
        {
            try
            {
                if(trickName.equals("handCuffs"))
                {
                    handCuffs = get();
                }
                else if(trickName.equals("cups"))
                {
                    cups = get();
                }
            }
            catch(InterruptedException ignore){}
            catch(java.util.concurrent.ExecutionException e)
            {
                String why = null;
                Throwable cause = e.getCause();
                if(cause != null)
                {
                    why = cause.getMessage();
                }
                else
                {
                    why = e.getMessage();
                }
                System.err.println("Error retrieving file: " + why);
            }
        }
    }

     /******************************************
     * End SwingWorker Pre-Loading Classes
     ******************************************/

    //Prints out time spent on each slide
    public void timeStamp()
    {
        time1 = System.currentTimeMillis();
        if(time0 != 0)
        {
            System.out.println(time1 - time0);
        }
        time0 = System.currentTimeMillis();
    } 

    /******************************************
     * User Input Classes for Key Binding Actions and Mouse Click Actions
     ******************************************/

    private class EscapeAction extends AbstractAction
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
            System.exit(0);
        }
    }

    public class Mouse extends MouseAdapter
    {
        @Override
        public void mouseClicked(MouseEvent e) 
        {
            if(!(h<handCuffs.length) && !(c<cups.length))
            {
                timeStamp();
                System.exit(0);
            }
            else if(h<handCuffs.length)
            {
                timeStamp();
                screenImage = handCuffs[h];
                repaint();
                System.out.print("handCuffs[" + (h+1) + "]\t");
                h++;
                //purge used slides and refresh slide buffer
                if(h == 20 || h == 40)
                {
                    for(int i = 0; i < h; i++)
                    {
                        handCuffs[i] = null;
                    }
                    start("handCuffs");
                }
                if(h == 45)
                {
                    start("cups");
                }
            }
            else if(c<cups.length)
            {
                timeStamp();
                screenImage = cups[c];
                repaint();
                System.out.print("cups[" + (c+1) + "]\t");
                c++;
                //purge used slides and refresh slide buffer
                if(c == 20 || c == 40 || c == 60 || c == 80 || c == 100 || c == 120 || c == 140 || c == 160)
                {
                    for(int i = 0; i < c; i++)
                    {
                        cups[i] = null;
                    }
                    start("cups");
                }
            }
        }
    }

    /******************************************
     * End User Input Classes for Key Binding Actions and Mouse Click Actions
     ******************************************/ 
}
4

1 回答 1

5

示例使用 aList<ImageIcon>作为cachegetImage(). 使用getResource(),延迟是不可察觉的。下一个和上一个按钮默认绑定到Space键。

setEnabled()附录:您可以通过使用 的实例来调节按钮的状态来控制导航javax.swing.Timer例如.

附录:您的第二个示例等到单击鼠标开始读取图像,这是一个不确定的过程,可能会立即返回副本,也可能要等到之后才能完成。相反,使用 开始阅读背景中的图像,如此所示。您可以显示进度,如此处所示。可以从初始线程启动,在您随后在 EDT 上构建 GUI 时运行。您可以在处理完第一张图像后立即显示它。 repaint()ImageIO.read()process()List<Image>SwingWorker

于 2013-01-05T21:01:21.220 回答