paint() 无法绘制 gif 但 png 可以正常工作?

Posted

技术标签:

【中文标题】paint() 无法绘制 gif 但 png 可以正常工作?【英文标题】:paint() can't draw gif but png works fine? 【发布时间】:2018-02-20 09:18:26 【问题描述】:

我正在使用 JLabel 尝试在其上绘制动画 gif 图像。我可以使用构造函数new JLabel(new ImageIcon(FML.class.getResource("giphy.gif")));,它会工作得很好,但是当我重写paint方法时,它似乎根本不想绘制它。图像不是静止的,它不存在!我应该提一下,下面显示的两种方法都适用于 PNG 但不适用于 GIF。我错过了什么还是这是一个java错误? (使用 java 1.8)

编辑:我一直在环顾四周,似乎我并没有完全偏离我需要做的事情,但我错过了一些东西。我看过很多帖子Like this one,但在这种情况下似乎不起作用。

我应该注意,课堂上实际上没有其他内容,它是一个简单的 JPanel。

    import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class FML 

    public static void main(String[] args) 
        new FML();
    

    public FML() 
        EventQueue.invokeLater(new Runnable() 
            @Override
            public void run() 
                try 
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                 catch (ClassNotFoundException ex) 
                 catch (InstantiationException ex) 
                 catch (IllegalAccessException ex) 
                 catch (UnsupportedLookAndFeelException ex) 
                

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.getContentPane().setLayout(new FlowLayout());
                frame.getContentPane().add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            
        );
    

    public class TestPane extends JPanel 

        private ImageIcon animatedGif;

        public TestPane() 
            setLayout(new GridBagLayout());
            JButton btn = new JButton(new ImageIcon(FML.class.getResource("FmDxW.png")));
            btn.setSize(50, 50);
            btn.setRolloverEnabled(true);
            animatedGif = new ImageIcon(FML.class.getResource("giphy.gif"));
            btn.setRolloverIcon(animatedGif);
            add(btn);

            btn.addMouseListener(new MouseAdapter() 

                @Override
                public void mouseEntered(MouseEvent e) 
                    animatedGif.getImage().flush();
                

            );

            //I need this
            final ImageIcon image = new ImageIcon(FML.class.getResource("giphy.gif"));

            //To render over this
            final ImageIcon image2 = new ImageIcon(FML.class.getResource("fmDxW.png"));


            //I'm not understanding why I can add the gif into the constructor but the paint method fails.
            JLabel label = new JLabel(image) 
                @Override
                public void paint(Graphics g) 
                    super.paint(g);
                    g.drawImage(image2.getImage(), 64, 64, this);
                
            ;
            //setSize because I want to be 100% sure that it's loading the correct size.
            //Removing it doesn't affect the problem at hand.
            label.setSize(64, 64);
            add(label);
        
    

【问题讨论】:

1) 您不应该在绘画方法中进行 I/O。 2) 自定义绘画(需要时)是通过覆盖paintComponent(...) 来完成的。 3)无需自定义绘制,只需在JLabel中添加一个Icon即可。 4) 不要在标签上使用 setSize(...)。这意味着您使用的是空布局。不要使用空布局。 Swing 旨在与布局管理器一起使用。阅读 Swing tutorial 了解 Swing 基础知识。有关于使用图标和自定义绘画的部分。 这只是测试代码,我永远不会在生产代码上使用 IO。话虽如此,在我的具体实现中确实需要自定义绘画。尽管如此,我还是尝试将 IO 移出渲染循环,因为这可能是问题所在,但没有骰子。问题依然存在。 -edit- 再次,这是测试代码,我知道如何使用布局管理器和自定义绘画并不复杂。我觉得我只是错过了一些具体的东西。 如果您知道如何使用布局管理器并进行自定义绘画,那么您应该没有问题,为什么要覆盖paint()?。但显然你确实有问题。我不知道您为什么要扩展 JLabel 以进行自定义绘画,以简单地尝试绘制图像。 JLabel 无需任何自定义即可为您执行此操作。我看到的所有代码都表明您不了解 Swing 的基础知识。发布正确的minimal reproducible example,使用正确的 Swing 技术演示问题。 在那里,我已经包含了整个班级并添加了 cmets 来帮助解释我正在尝试做的事情。 【参考方案1】:
g.drawImage(image2.getImage(), 64, 64, this);

假设您的图片大小为 64,您为什么要尝试在标签范围之外绘制第二张图片?当我将位置更改为 (0, 0) 时,gif 对我来说很好(但我没有使用动画 gif)。

下面显示的两种方法都适用于 PNG 但不适用于 GIF。

我不明白我上面给出的原因。不管怎样,你用普通的 gif 试过了吗?

这就是为什么您不应该尝试自己管理绘画的原因,因为现在您需要担心位置并且硬编码位置不是一个好习惯。让您的布局管理器为您执行此操作。

再说一遍,你为什么要这样做。你为什么要覆盖paint方法来绘制第二张图像?

相反,您应该这样做:

    在 paintComponent() 方法中绘制两个图像 使用带有OverlayLayout 的面板,然后您可以将两个标签堆叠在一起。 您甚至可以将布局的布局管理器设置为 GridBagLayout 之类的东西,然后当您将 JLabel 添加到标签时,它会自动居中。

//setSize 因为我想 100% 确定它正在加载正确的大小。

您说您知道布局管理器的工作原理。好吧,如果你这样做了,那么你知道这个语句不会做任何事情,因为布局管理器将覆盖你设置的任何值,所以使用这样的代码是错误的,并且显示出基本缺乏理解,并且不应该包含在 MCVE 中MCVE`的目的就是尽可能的简化问题。

【讨论】:

以上是关于paint() 无法绘制 gif 但 png 可以正常工作?的主要内容,如果未能解决你的问题,请参考以下文章

使用 gdi+ 进行无闪烁绘图

图片优化

pyagme 图像/图形绘制

QT 三大绘图类:QPixmap/QImage/QPicture

Android自定义View画图的步骤及关于CanvasBitmapPaint的关系

PHP GD 库中不支持 PNG,但支持 GIF 和 JPEG。我怎样才能解决这个问题?