An animated (cycling) GIF can be displayed in a JLabel
or in HTML (in formatted text components like JEditorPane
) and be seen to cycle.
But to load an image to paint as the background of a container, I would typically use either ImageIO.read()
or Toolkit.getImage()
(the latter when I'm feeling nostalgic for the last millennium). Neither method of loading an image results in a cycling image, it is typically just the first frame.
How to load an animated image for a background?
E.G.
To get a cycling (animated) GIF for custom painting, one trick is to load it using an ImageIcon
. While the image returned from either of the two methods listed in the question is static, one obtained from an ImageIcon
is animated.
The code below will add 50 buttons, then soon after the frames of the 'zooming stars' animated GIF1 as BG to them. The ImagePanel
will stretch the image to the size of the panel.
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);
}
});
}
}
Using ImageIcon
is probably the most straightforward thing to do. A couple of things to keep in mind:
ImageIcon(URL)
itself makes use of Toolkit.getImage(URL)
. You may prefer using Toolkit.createImage(URL)
instead - getImage()
may use cached or shared image data.
ImageIcon
makes use of a MediaTracker
to effectively wait until the image is completely loaded.
So, your issue may not be the use of Toolkit
(ImageIO
is a different beast), but rather the fact that you're not rendering a fully loaded image. One interesting thing to try would be:
Image image = f.getToolkit().createImage(url);
//...
ImagePanel imagePanel = new ImagePanel(image);
imagePanel.prepareImage(image, imagePanel);
//...
My Swing/AWT/J2D may be a bit fuzzy, but the idea is that since your ImagePanel
is an ImageObserver
, it can be notified asynchronously about image information. The Component.imageUpdate()
method should invoke repaint
as needed.
Edit:
As noted in the comments, the call to prepareImage
is not required - a working example is included below. The key is that the overridden paintComponent
method invokes Graphics.drawImage
, which provides the ImageObserver
hook. The imageUpdate
method (implemented in java.awt.Component
) will continuously be invoked with the ImageObserver.FRAMEBITS
flag set.
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);
}
});
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With