一个循环播放的 GIF 可以在 JLabel
中显示,也可以在 HTML(如 JEditorPane
)中以格式化文本组件的形式显示,并循环播放。
但是要加载一张图片作为容器的背景来绘制,我通常会使用 ImageIO.read()
或 Toolkit.getImage()
(后者让我怀念上个千年)。这两种加载图像的方法都不会产生循环播放的图像,通常只有第一帧。
如何加载一个 动画 图像作为背景呢?
例如:
一个循环播放的 GIF 可以在 JLabel
中显示,也可以在 HTML(如 JEditorPane
)中以格式化文本组件的形式显示,并循环播放。
但是要加载一张图片作为容器的背景来绘制,我通常会使用 ImageIO.read()
或 Toolkit.getImage()
(后者让我怀念上个千年)。这两种加载图像的方法都不会产生循环播放的图像,通常只有第一帧。
如何加载一个 动画 图像作为背景呢?
例如:
ImageIcon
加载它。虽然从问题中列出的两种方法返回的图像是静态的,但从 ImageIcon
获得的图像是动画的。ImagePanel
将拉伸图像到面板的大小。
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.net.URL;
class ImagePanel extends JPanel {
private Image image;
ImagePanel(Image image) {
this.image = image;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image,0,0,getWidth(),getHeight(),this);
}
public static void main(String[] args) throws Exception {
URL url = new URL("http://i.stack.imgur.com/iQFxo.gif");
final Image image = new ImageIcon(url).getImage();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Image");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationByPlatform(true);
ImagePanel imagePanel = new ImagePanel(image);
imagePanel.setLayout(new GridLayout(5,10,10,10));
imagePanel.setBorder(new EmptyBorder(20,20,20,20));
for (int ii=1; ii<51; ii++) {
imagePanel.add(new JButton("" + ii));
}
f.setContentPane(imagePanel);
f.pack();
f.setVisible(true);
}
});
}
}
使用ImageIcon
可能是最简单的方法。需要记住几件事:
ImageIcon(URL)
本身使用了 Toolkit.getImage(URL)
。你可能更喜欢使用 Toolkit.createImage(URL)
- getImage()
可能会使用缓存或共享的图像数据。
ImageIcon
使用 MediaTracker
来等待图像完全加载。
所以,你的问题可能不在于使用 Toolkit
(ImageIO
是一个不同的东西),而在于你没有渲染完全加载的图像。尝试有趣的一件事是:
Image image = f.getToolkit().createImage(url);
//...
ImagePanel imagePanel = new ImagePanel(image);
imagePanel.prepareImage(image, imagePanel);
//...
我的Swing/AWT/J2D可能有点模糊,但是关键在于由于你的ImagePanel
是一个ImageObserver
,所以它可以异步地被通知图像信息。 Component.imageUpdate()
方法应根据需要调用repaint
。
编辑:
如评论中所述,不需要调用prepareImage
- 下面包含了一个可行的示例。关键在于覆盖的paintComponent
方法调用了Graphics.drawImage
,提供了ImageObserver
钩子。imageUpdate
方法(在java.awt.Component
中实现)将不断使用ImageObserver.FRAMEBITS
标志设置。
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class ImagePanel extends JPanel {
private final Image image;
public ImagePanel(Image image) {
super();
this.image = image;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(this.image, 0, 0, getWidth(), getHeight(), this);
}
public static void main(String[] args) throws MalformedURLException {
final URL url = new URL("http://i.stack.imgur.com/iQFxo.gif");
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame f = new JFrame("Image");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationByPlatform(true);
Image image = f.getToolkit().createImage(url);
ImagePanel imagePanel = new ImagePanel(image);
imagePanel.setLayout(new GridLayout(5, 10, 10, 10));
imagePanel.setBorder(new EmptyBorder(20, 20, 20, 20));
for (int ii = 1; ii < 51; ii++) {
imagePanel.add(new JButton("" + ii));
}
f.setContentPane(imagePanel);
f.pack();
f.setVisible(true);
}
});
}
}
Toolkit.createImage(URL)
作为new ImageIcon(url).getImage()
的直接替代品,图片也能够循环。请注意,我没有打算调用prepareImage
。 - Andrew Thompsonprivate JPanel loadingPanel() {
JPanel panel = new JPanel();
BoxLayout layoutMgr = new BoxLayout(panel, BoxLayout.PAGE_AXIS);
panel.setLayout(layoutMgr);
ClassLoader cldr = this.getClass().getClassLoader();
java.net.URL imageURL = cldr.getResource("img/spinner.gif");
ImageIcon imageIcon = new ImageIcon(imageURL);
JLabel iconLabel = new JLabel();
iconLabel.setIcon(imageIcon);
imageIcon.setImageObserver(iconLabel);
JLabel label = new JLabel("Loading...");
panel.add(iconLabel);
panel.add(label);
return panel;
}