【问题标题】:Knowing when GIF is done playing知道 GIF 何时播放完毕
【发布时间】:2017-06-23 23:22:02
【问题描述】:

我正在尝试将 GIF 文件显示到 JLabel。没问题我加载GIF并将其设置为标签的图标。但现在我真的需要知道什么时候结束,因为它必须充当过场动画。我已经尝试过的是这个(GameScene 是一个自定义对象,但我知道 setIcon 有效,相信我):

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();
    }
}

现在,我有没有办法做到这一点,只需让整个程序休眠给定的时间,然后继续执行其余代码并且完全不绘制 GIF 文件?

【问题讨论】:

  • 不是以“直截了当”开头的问题。
  • 你没看错吧?

标签: java animation gif


【解决方案1】:

这是一个非常简单的示例,它仅适用于非循环 gif,如果您的 gif 重复,您将必须测试 FRAMEBITS 请求之间的时间并尝试确定您是否可以检测到循环。

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;
    }

}

上面的类提供了一个ActionListener,它在图像“完成”加载时触发(当它们在动画中没有新帧时触发 - 重复的 gif 永远不会返回 false

如果你愿意,你可以使用不同的监听器接口,我只是把它放在一起作为例子。

我选择覆盖imageUpdate 的原因是因为JLabel 在绘制图像时已经充当了图像的ImageObserver,这样我们就可以使用JLabel 的强大功能而不必大惊小怪手动绘制 gif ... 是的,我已经完成了,这很痛苦

【讨论】:

  • 可以通过在每次传递 FRAMEBITS 标志时增加一个计数器来处理循环 gif,并且仅在达到帧数时触发操作。
  • @teppic 假设您知道帧数,这不是最容易获得的东西,您可以“等待”一段时间,“希望”它的“大约”正确二,但同样,它假设一定数量的知识
  • @MadProgrammer 我会试一试,但我目前不在家。
  • @MadProgrammer 谢谢!这完全符合我的要求,谢谢。
  • 我究竟如何使用这个例子?我该怎么做才能让 GIF 动画的信号停止?请给我举个例子,我完全一无所知。抱歉,我 5 天前才开始使用 Java 编码。
【解决方案2】:

是否可以使用制作它的程序使 GIF 不重复?大多数制作 GIF 图像的照片编辑器都可以让您选择是否重复。

如果我理解您的问题,您似乎只想让 gif 播放一次?

如果是过场动画,为什么不在这段时间让程序休眠呢?

【讨论】:

  • 这正是您在我的代码中看到的问题,它由用户提供了一段时间的睡眠,但由于某种原因它只是暂停了整个程序。这就是我打算做的。但这变得更有帮助了:D
  • 好吧,sleep 确实会在调用它的那一刻暂停整个程序,持续设定的毫秒数。我认为我没有完全理解这里的问题。如果您需要一个包罗万象的解决方案来计算 gif 本身的长度,我在 Java 文档中找到了可能对您有所帮助的 imageObserver 和 imageReader 类。具体来说:docs.oracle.com/javase/7/docs/api/java/awt/image/…
  • @JarnoGabriël 这是因为 Swing 是单线程的,使用 Thread.sleep 会阻塞主线程,阻止它更新 UI。您需要使用 Swing Timer 进行此类操作
  • 谢谢!我不知道主线程被阻塞。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多