10

动画(循环)GIF 可以以JLabelHTML 格式或 HTML 格式显示(在格式文本组件中,如JEditorPane),并且可以看到循环。

但是要加载图像以绘制为容器的背景,我通常会使用ImageIO.read()Toolkit.getImage()(当我怀念上个千年时,后者)。这两种加载图像的方法都不会导致循环图像,它通常只是第一帧。

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

例如

4

3 回答 3

16

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

下面的代码将添加 50 个按钮,然后在“缩放星星”动画 GIF 1的帧之后作为背景添加到它们。ImagePanel会将图像拉伸到面板的大小。

  1. 它基于此图像。

缩放星星 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);
            }
        });
    }
}
于 2012-05-31T15:40:15.553 回答
13

使用ImageIcon可能是最直接的事情。要记住几件事:

  • ImageIcon(URL)本身利用Toolkit.getImage(URL). 您可能更喜欢使用Toolkit.createImage(URL)-getImage()可以使用缓存或共享的图像数据。

  • ImageIcon使用 aMediaTracker有效地等待图像完全加载。

因此,您的问题可能不是使用Toolkit( ImageIOis a different beast),而是您没有渲染完全加载的图像这一事实。一件有趣的事情是:

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);
            }
        });
    }
}
于 2012-05-31T18:57:08.667 回答
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,它就像一个魅力。

于 2013-03-01T20:38:37.223 回答