java 在 Swing 中显示动画 BG

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10836832/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 02:47:33  来源:igfitidea点击:

Show an animated BG in Swing

javaimageswingbackgroundanimated-gif

提问by Andrew Thompson

An animated (cycling) GIF can be displayed in a JLabelor in HTML (in formatted text components like JEditorPane) and be seen to cycle.

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

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.

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

How to load an animatedimage for a background?

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

E.G.

例如

回答by Andrew Thompson

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 ImageIconis animated.

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

The code below will add 50 buttons, then soon after the frames of the 'zooming stars' animated GIF1as BG to them. The ImagePanelwill stretch the image to the size of the panel.

下面的代码将添加 50 个按钮,然后在“缩放星星”动画 GIF 1的帧之后添加它们作为 BG。在ImagePanel将图像回复到面板的尺寸。

  1. It is based on this image.
  1. 它基于此图像。

Zooming Stars GIF

放大星星 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);
            }
        });
    }
}

回答by kschneid

Using ImageIconis probably the most straightforward thing to do. A couple of things to keep in mind:

使用ImageIcon可能是最直接的事情。请记住以下几点:

  • 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.

  • ImageIconmakes use of a MediaTrackerto effectively wait until the image is completely loaded.

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

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

So, your issue may not be the use of Toolkit(ImageIOis a different beast), but rather the fact that you're not rendering a fully loaded image. One interesting thing to try would be:

因此,您的问题可能不是使用Toolkit(ImageIO是一个不同的野兽),而是您没有渲染完全加载的图像这一事实。尝试的一件有趣的事情是:

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 ImagePanelis an ImageObserver, it can be notified asynchronously about image information. The Component.imageUpdate()method should invoke repaintas needed.

我的 Swing/AWT/J2D 可能有点模糊,但思路是,既然你ImagePanel是一个ImageObserver,它可以异步通知图像信息。该Component.imageUpdate()方法应repaint根据需要调用。

Edit:

编辑:

As noted in the comments, the call to prepareImageis not required - a working example is included below. The key is that the overridden paintComponentmethod invokes Graphics.drawImage, which provides the ImageObserverhook. The imageUpdatemethod (implemented in java.awt.Component) will continuously be invoked with the ImageObserver.FRAMEBITSflag set.

正如评论中所指出的,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);
            }
        });
    }
}

回答by Paulo Pedroso

I managed to get the animated gif inside my JPanel this way:

我设法通过这种方式在我的 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;
}

Some points of this approach:
1. The image file is within the jar;
2. ImageIO.read() returns a BufferedImage, which doesn't update the ImageObserver;
3. Another alternative to find images that are bundled in the jar file is to ask the Java class loader, the code that loaded your program, to get the files. It knows where things are.

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

So by doing this I was able to get my animated gif inside my JPanel and it worked like a charm.

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