Knowing when GIF is done playing

2019-09-07 00:31发布

问题:

I'm trying to display a GIF file to a JLabel. No problem I load the GIF and set it as the icon of the label. But now i really need to know when this ends, because it has to function as a cutscene. What i already tried is this (GameScene is a custom object but i know setIcon works, trust me) :

private GameScene scene;
private ImageIcon _temp;
private ImageIcon toplay;
private Thread anim;

public Cutscene(ImageIcon gif, GameScene scene, int length){
    this._temp = scene.getIcon();
    this.toplay = gif;
    this.scene = scene;
    anim = new Thread(){
        @Override
        public void run(){
            scene.setIcon(gif);
            scene.repaint();
            try {
                Thread.sleep(length);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
}

private void _s(){
    scene.setSolidColor(false);
    scene.setIcon(toplay);
    scene.repaint();
}

public void play(){
    _s();
    anim.start();
}

public void await(){
    try {
        anim.join();
        scene.setIcon(_temp);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

Now, Is there anyway I can achieve this without, just letting the whole program sleep for the given amount of time and then continue with the rest of the code and completely not drawing the GIF file?

回答1:

This is a really simply example, it will only work with non-looping gifs, if your gif repeats you'll have to test the time between requests for FRAMEBITS and try and determine if you can detect the point at which loops.

public class MonitoringLabel extends JLabel {

    public MonitoringLabel(Icon image) {
        super(image);
    }

    public void addActionListener(ActionListener listener) {
        listenerList.add(ActionListener.class, listener);
    }

    public void removeActionListener(ActionListener listener) {
        listenerList.remove(ActionListener.class, listener);
    }

    protected void fireActionPerformed() {
        ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
        if (listeners.length > 0) {
            ActionEvent evt = new ActionEvent(this, 0, "stopped");
            for (ActionListener listener : listeners) {
                listener.actionPerformed(evt);
            }
        }
    }

    @Override
    public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
        boolean finished = super.imageUpdate(img, infoflags, x, y, w, h);
        if (!finished) {
            fireActionPerformed();
        }
        return finished;
    }

}

The above class provides an ActionListener which is triggered when the image "finishes" loading (this is triggered when their are no new frames in the animation to be played - repeating gifs never return false)

You can use a different listener interface if you want, I just threw it together as an example.

The reason I choose to override imageUpdate is because the JLabel is already acting as the ImageObserver to the image when it paints it, this way we can use the power of the JLabel without fussing about with manually painting a gif ... yes I've done it, it's pain



回答2:

Would it be possible to make the GIF non-repeating with the program used to make it? Most photo editors that make GIF images give you the option of making it repeating or not.

If I'm understanding your problem, it seems like you just want the gif to play once?

If it's for a cut scene, why not make the program sleep during that time?