2015-12-07 7 views
0

У меня есть изображение gif, отображаемое на JPanel в бесконечном цикле. Теперь мне нужно остановить анимацию после случайного количества кадров. Фактически, я генерирую случайное число, которое может быть 0 или 1. Скажем, что gif состоит из 6 кадров. Если число равно 0, я хочу остановиться на 3-м кадре, если он равен 1, анимация должна зависнуть на 6-м кадре.синхронизировать качающийся таймер с gif Изображение

Чтобы реализовать это, я попытался использовать таймер Swing, который запускает события точно, когда приходит следующий кадр. Таким образом, если кадры имеют задержку в 50 мс, я построить таймер, как

new Timer(50, this); 

К сожалению, это не похоже на работу, на самом деле анимация, кажется медленнее, чем таймер. (Я предполагаю, что это имеет какое-то отношение к загрузке Times). Во всяком случае, я добавил код, иллюстрирующий подход «Проблема и (неудача) решения».

import java.awt.event.*; 
import javax.swing.*; 

public class GifTest extends JPanel implements ActionListener{ 

ImageIcon gif = new ImageIcon(GifTest.class.getResource("testgif.gif")); 
JLabel label = new JLabel(gif); 
Timer timer = new Timer(50, this); 
int ctr; 

public GifTest() { 
    add(label); 
    timer.setInitialDelay(0); 
    timer.start(); 
} 

@Override 
public void actionPerformed(ActionEvent e) { 
    ctr++; 
    if (ctr == 13){ 
     timer.stop(); 
     try { 
      Thread.sleep(1000); 
     } catch (InterruptedException i) { 
     } 
    } 
} 

public static void main(String[] args) { 
    JFrame frame = new JFrame("Gif Test"); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.add(new GifTest()); 
    frame.setSize(150,150); 
    frame.setLocationRelativeTo(null); 
    frame.setVisible(true); 
} 
} 

Для giftest.gif, это просто 6 слоев с номерами от 1 до 6 на них, спасенных с задержкой 50 мс.

Я был бы признателен за любую помощь.

Пс: Если окажется, что нет элегантного способа сделать это, также будет достаточно получить отображаемый в настоящее время фрейм. Таким образом, я мог бы попросить об этом и остановиться, когда это третий (соответственно 6-й) кадр. Из-за контекста задачи я предпочел бы модифицированную версию моего решения.

+2

В худшем случае распакуйте изображения из GIF и отобразите каждое изображение с помощью таймера поворота. –

+0

Зачем вам Thread.sleep (1000)? –

+0

Просто чтобы не допустить, чтобы анимация продолжалась в ближайшее время, так что я могу видеть, что представляет собой 13-й кадр. – Kenji

ответ

0

Вы можете распаковать, как указано выше, и сохранить в массиве изображений (простых и простых).
Вы можете также использовать более продвинутый вариант с использованием ImageObserver интерфейса:
ImageObserver обеспечивает контроль за процессом загрузки через специальный API под названием:
imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
Вы можете отслеживать прогресс с этим API следующим образом:

ImageIcon gif = new ImageIcon(); 
JLabel label = new JLabel(gif); 
ImageObserver myObserver = new ImageObserver() { 
     public boolean imageUpdate(Image image, int flags, int x, int y, int width, int height) { 
     if ((flags & HEIGHT) != 0) 
      System.out.println("Image height = " + height); 
     if ((flags & WIDTH) != 0) 
      System.out.println("Image width = " + width); 
     if ((flags & FRAMEBITS) != 0) 
      System.out.println("Another frame finished."); 
     if ((flags & SOMEBITS) != 0) 
      System.out.println("Image section :" + new Rectangle(x, y, width, height)); 
     if ((flags & ALLBITS) != 0) 
      System.out.println("Image finished!"); 
     if ((flags & ABORT) != 0) 
      System.out.println("Image load aborted..."); 
     label.repaint(); 
     return true; 
     } 
    }; 
gif.setImageObserver(myObserver); 
gif.setImage(GifTest.class.getResource("testgif.gif")); 

Вы можете остановить процесс загрузки, используя return false;

UPDATE: (используя ImageReader)
ImageObserver не так интуитивно понятен для работы.
Он будет обновляться каждый раз, когда требуется перекраска, и будет запущена полная последовательность анимации.
Хотя вы можете остановить его как точку, он будет выполняться с первого изображения каждый раз.

Другим решением является использование ImageReader:
ImageReader может распаковать GIF в последовательность BufferedImages.
После этого вы можете управлять всей последовательностью с помощью таймера по своему усмотрению.

String gifFilename = "testgif.gif"; 
    URL url = getClass().getResource(gifFilename); 
    ImageInputStream iis = new FileImageInputStream(new File(url.toURI())); 
    ImageReader reader = ImageIO.getImageReadersByFormatName("GIF").next(); 
    // (reader is actually a GIFImageReader plugin) 
    reader.setInput(iis); 
    int total = reader.getNumImages(true); 
    System.out.println("Total images: "+total); 
    BufferedImage[] imgs = new BufferedImage[total]; 

    for (int i = 0; i < total; i++) { 
     imgs[i] = reader.read(i); 
     Icon icon = new ImageIcon(imgs[i]); 
     // JLabel l = new JLabel(icon)); 
    } 
+0

Спасибо @ Leet-Falcon. Насколько я понял, метод imageUpdate должен вызываться всякий раз, когда отображается следующий кадр ?! Это действительно не работает для меня. Печать счетчика, увеличивающегося в методе, и сравнение с фактическим gif, отображаемым на моем JPanel, показывает, что эти два варианта по-прежнему асинхронны. – Kenji

+0

@ Kenji см. Мое обновление –

 Смежные вопросы

  • Нет связанных вопросов^_^