在Swing中显示动画BG

时间:2012-05-31 15:40:15

标签: java image swing background animated-gif

动画(骑行)GIF可以JLabel或HTML格式显示(在JEditorPane等格式化文本组件中),并且可以循环播放。

但是要加载图像作为容器的背景绘制,我通常会使用ImageIO.read()Toolkit.getImage()(后者在我感觉上一个千年怀旧时)。加载图像的方法都不会产生循环图像,通常只是第一帧。

如何为背景加载动画图像?

3 个答案:

答案 0 :(得分:15)

要获得自定义绘画的循环(动画)GIF,一个技巧是使用 ImageIcon 加载它。虽然从问题中列出的两种方法中的任何一种返回的图像都是静态的,但是从ImageIcon获得的图像是动画的。

下面的代码将添加50个按钮,然后很快将'缩放星'的动画GIF 1 的帧作为BG给他们。 ImagePanel会将图片拉伸到面板的大小。

  1. 基于此图片。
  2. Zooming Stars GIF

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

答案 1 :(得分:12)

使用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可能有点模糊,但我们的想法是,由于您的ImagePanelImageObserver,因此可以异步通知图像信息。 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://pscode.org/media/starzoom-thumb.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);
            }
        });
    }
}

答案 2 :(得分:1)

我设法以这种方式在我的JPanel中获得动画gif:

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

这种方法的一些要点:
1.图像文件在jar内;
2. ImageIO.read()返回一个BufferedImage,它不会更新ImageObserver;
3.找到捆绑在jar文件中的图像的另一种方法是询问Java类加载器,即加载程序的代码,以获取文件。它知道事物的位置。

通过这样做,我能够在我的JPanel中获得我的动画gif,它就像一个魅力。