将 Swing Timer 与 gif 图像同步
synchronize Swing Timer with gif Image
我有一个 gif 图像在无限循环中显示在 JPanel 上。现在我需要在随机数量的帧之后停止动画。事实上,我生成了一个可以为 0 或 1 的随机数。假设 gif 包含 6 个帧。如果数字是 0,我想在第 3 帧停止,如果它是 1,动画应该在第 6 帧停止。
为了实现这一点,我尝试使用 Swing Timer,它会在下一帧到来时准确触发事件。所以如果 Frames 有 50 ms 的延迟,我会构造像
这样的 Timer
new Timer(50, this);
遗憾的是,这似乎不起作用,事实上动画似乎比计时器慢。 (我认为这与加载时间有关。)无论如何,我添加了一些代码来说明问题和(失败)解决方法。
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,延迟50ms保存。
如有任何帮助,我将不胜感激。
Ps:如果发现没有什么优雅的办法,也可以取回当前显示的Frame。这样我就可以要求它并在它是第 3 个(resp。第 6 个)帧时停止。由于任务的上下文,我更喜欢我的解决方案的修改版本。
你可以像上面提到的那样解压并存储在一个图像数组中(简单明了)。
您还可以使用更高级的选项 ImageObserver Interface:
ImageObserver 通过名为 API 的特殊 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;
停止加载过程
更新:(使用 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));
}
我有一个 gif 图像在无限循环中显示在 JPanel 上。现在我需要在随机数量的帧之后停止动画。事实上,我生成了一个可以为 0 或 1 的随机数。假设 gif 包含 6 个帧。如果数字是 0,我想在第 3 帧停止,如果它是 1,动画应该在第 6 帧停止。
为了实现这一点,我尝试使用 Swing Timer,它会在下一帧到来时准确触发事件。所以如果 Frames 有 50 ms 的延迟,我会构造像
这样的 Timernew Timer(50, this);
遗憾的是,这似乎不起作用,事实上动画似乎比计时器慢。 (我认为这与加载时间有关。)无论如何,我添加了一些代码来说明问题和(失败)解决方法。
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,延迟50ms保存。
如有任何帮助,我将不胜感激。
Ps:如果发现没有什么优雅的办法,也可以取回当前显示的Frame。这样我就可以要求它并在它是第 3 个(resp。第 6 个)帧时停止。由于任务的上下文,我更喜欢我的解决方案的修改版本。
你可以像上面提到的那样解压并存储在一个图像数组中(简单明了)。
您还可以使用更高级的选项 ImageObserver Interface:
ImageObserver 通过名为 API 的特殊 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;
更新:(使用 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));
}