如何将图像添加到JPanel?

367

我有一个JPanel,我想在上面添加我动态生成的JPEG和PNG图像。

到目前为止,我看到的所有示例都是在Swing教程中,特别是在Swing示例中使用ImageIcon

我将这些图像作为字节数组生成,并且通常比示例中使用的普通图标大,大小为640x480。

  1. JPanel中使用ImageIcon类显示那么大的图像是否会有任何(性能或其他)问题?
  2. 通常的做法是什么?
  3. 如何在不使用ImageIcon类的情况下向JPanel添加图像?

编辑:对教程和API的更仔细检查表明,您无法直接将ImageIcon添加到JPanel中。相反,他们通过将图像设置为JLabel的图标来实现相同的效果。这感觉不太对...


1
根据您生成字节数组的方式,使用MemoryImageSource可能比将它们转换为JPEG或PNG格式并像大多数答案建议的那样使用ImageIO读取更有效率。您可以使用createImage从构造有图像数据的MemoryImageSource中获取一个Image,并按照其中一个答案所建议的方式进行显示。 - Alden
请检查我的答案 http://stackoverflow.com/questions/43861991/how-to-put-an-image-from-a-jfilechooser/43862895#43862895 - tommybee
14个回答

547

如果您正在使用JPanels,则可能正在使用Swing。尝试这样做:

BufferedImage myPicture = ImageIO.read(new File("path-to-file"));
JLabel picLabel = new JLabel(new ImageIcon(myPicture));
add(picLabel);

现在该图片是一个Swing组件了,它会像其他组件一样受到布局条件的影响。


20
如何根据JLabel的大小缩放图像? - coding_idiot
2
不错的代码!我对Swing不是很有经验,但我无法让它工作。有人在jdk 1.6.0_16中尝试过吗? - ATorras
4
@ATorras,我知道你之前问过这个问题,但如果有其他初学者遇到了我的问题,请记得使用picLabel.setBounds(); - kyle
4
@coding_idiot:新建一个 JLabel,将其设置为指定宽高并使用快速缩放模式(Image.SCALE_FAST)加载背景图片。 - Davide
2
@ATorras 你提出那个问题已经有一段时间了。但或许这会对未来的其他人有所帮助。对我来说它也没起作用。我使用了一个 .ico 图像。然后我尝试了一个 .png 图像,它对我起作用了。 :) - thankyou
显示剩余2条评论

265

以下是我如何做到的(包括有关如何加载图像的更多信息):

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class ImagePanel extends JPanel{

    private BufferedImage image;

    public ImagePanel() {
       try {                
          image = ImageIO.read(new File("image name and path"));
       } catch (IOException ex) {
            // handle exception...
       }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, this); // see javadoc for more info on the parameters            
    }

}

20
对于 paintComponent 的无效实现,应该返回 -1(@Dogmatixed 很可能之所以出现重绘问题是因为这个原因)——如果它报告自己不透明(默认情况下),那么它必须确保覆盖其完整的区域。最简单的方法是调用 super.paintComponent。 - kleopatra
6
@kleopatra,谢谢,我之前没有意识到... 根据javadoc的描述:“此外,如果您不调用super的实现,则必须遵守opaque属性,也就是说,如果此组件是opaque的,那么您必须使用非opaque颜色完全填充背景。 如果您不遵守opaque属性,则可能会看到视觉伪影。” 我现在会更新答案。 - Brendan Cashman
9
在重写超级类的方法时,请始终遵守"封装原则",而paintComponent(...)方法的访问修饰符为protected而不是public :-) - nIcE cOw
1
这样不行,它没有对面板大小和图像进行任何调整。稍后需要添加更多代码来处理这个问题。使用JLabel答案要简单得多。 - Keilly
3
@Jonathan:非常抱歉,关于“封装原则”的一些资源问题。只需记住,在编程时,应该隐藏其他代码所需隐藏的内容,而不是让所有代码都可以看到。看起来这是一种需要通过经验才能获得的东西,因为我们每天都在学习。任何书籍都可以给出封装的基本概念,但是我们如何实现代码决定了我们遵循这个概念的程度。 - nIcE cOw
显示剩余2条评论

41

Fred Haslam的方法很好用。不过,我有些问题是关于文件路径,因为我想引用我的jar包中的一张图片。为了实现这个目的,我使用了:

BufferedImage wPic = ImageIO.read(this.getClass().getResource("snow.png"));
JLabel wIcon = new JLabel(new ImageIcon(wPic));

我只有有限数量(大约10张)的图片需要使用这种方法加载,所以它非常有效。 它可以获取文件而不必拥有正确的相对文件路径。


2
我用BufferedImage previewImage = ImageIO.read(new URL(imageURL));替换了第一行,以从服务器获取我的图像。 - intcreator
要从JAR引用图像,请尝试使用以下方法:https://dev59.com/caPia4cB1Zd3GeqPsQp5#44844922 - Nandha

33

我认为没有必要去子类化任何东西,只需使用JLabel即可。您可以将图像设置到JLabel中,然后调整JLabel的大小并填充它的图像即可。这是我处理的方式。


19

你可以使用免费的SwingX库中的JXImagePanel类,完全避免自己创建组件子类。

下载


11
JLabel imgLabel = new JLabel(new ImageIcon("path_to_image.png"));

7
  1. 除了可能存在的大图像通用问题外,不应该有任何问题。
  2. 如果您想在单个面板中添加多个图像,我建议使用ImageIcon。对于单个图像,我会考虑创建一个自定义的JPanel子类,并覆盖其paintComponent方法以绘制图像。
  3. (请参见2)

7

您可以继承JPanel - 这是我的ImagePanel的一个片段,它可以将图像放置在五个位置之一:左上角、右上角、中间、左下角或右下角:

protected void paintComponent(Graphics gc) {
    super.paintComponent(gc);

    Dimension                           cs=getSize();                           // component size

    gc=gc.create();
    gc.clipRect(insets.left,insets.top,(cs.width-insets.left-insets.right),(cs.height-insets.top-insets.bottom));
    if(mmImage!=null) { gc.drawImage(mmImage,(((cs.width-mmSize.width)/2)       +mmHrzShift),(((cs.height-mmSize.height)/2)        +mmVrtShift),null); }
    if(tlImage!=null) { gc.drawImage(tlImage,(insets.left                       +tlHrzShift),(insets.top                           +tlVrtShift),null); }
    if(trImage!=null) { gc.drawImage(trImage,(cs.width-insets.right-trSize.width+trHrzShift),(insets.top                           +trVrtShift),null); }
    if(blImage!=null) { gc.drawImage(blImage,(insets.left                       +blHrzShift),(cs.height-insets.bottom-blSize.height+blVrtShift),null); }
    if(brImage!=null) { gc.drawImage(brImage,(cs.width-insets.right-brSize.width+brHrzShift),(cs.height-insets.bottom-brSize.height+brVrtShift),null); }
    }

6

这个答案是对@shawalli的答案的补充...

我也想在我的jar文件中引用一个图像,但是我不想使用BufferedImage,我只需要这样:

 JPanel jPanel = new JPanel();      
 jPanel.add(new JLabel(new ImageIcon(getClass().getClassLoader().getResource("resource/images/polygon.jpg"))));

6

JPanel 几乎总是不应该被继承的类。为什么不继承 JComponent 呢?

ImageIcon 存在一个小问题,即构造函数会阻塞读取图像。当从应用程序 jar 文件中加载时并不是真正的问题,但是如果你可能从网络连接中读取,则可能存在问题。有许多 AWT 时代的示例使用 MediaTrackerImageObserver 等工具,甚至在 JDK 演示中也有。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接