Java 如何将图像添加到JPanel?

Java 如何将图像添加到JPanel?,java,image,swing,jpanel,Java,Image,Swing,Jpanel,我有一个可以添加动态生成的JPEG和PNG图像的文件夹 到目前为止,我在中看到的所有示例,特别是在使用ImageIcons中 我将这些图像生成为字节数组,它们通常比示例中使用的常用图标(640x480)大 使用ImageIcon类在JPanel中显示大小相同的图像是否存在任何(性能或其他)问题 通常的做法是什么 如何在不使用ImageIcon类的情况下将图像添加到JPanel 编辑:对教程和API进行更仔细的检查后发现,您无法将图像图标直接添加到JPanel。相反,它们通过将图像设置为JLabe

我有一个可以添加动态生成的JPEG和PNG图像的文件夹

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

我将这些图像生成为字节数组,它们通常比示例中使用的常用图标(640x480)大

  • 使用ImageIcon类在JPanel中显示大小相同的图像是否存在任何(性能或其他)问题
  • 通常的做法是什么
  • 如何在不使用ImageIcon类的情况下将图像添加到JPanel

  • 编辑:对教程和API进行更仔细的检查后发现,您无法将图像图标直接添加到JPanel。相反,它们通过将图像设置为JLabel的图标来实现相同的效果。这感觉不对劲…

    您可以将JPanel子类化-这里是我的ImagePanel的摘录,它将图像放在5个位置中的任意一个,上/左、上/右、中/中、下/左或下/右:

    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); }
        }
    
  • 应该没有任何问题(除了非常大的图像可能存在的任何一般问题)
  • 如果您要在单个面板中添加多个图像,我会使用
    ImageIcon
    s。对于单个图像,我会考虑创建
    JPanel
    的自定义子类,并覆盖其
    paintComponent
    方法来绘制图像
  • (见第2条)
  • 下面是我的操作方法(还有一些关于如何加载图像的信息):


    JPanel
    对于子类来说几乎总是错误的类。为什么不将
    JComponent子类化


    ImageIcon
    有一个小问题,构造器会阻止读取图像。从应用程序jar加载时,这不是一个真正的问题,但如果您可能正在通过网络连接进行读取,则可能会出现问题。AWT时代有很多使用
    MediaTracker
    ImageObserver
    和朋友的例子,甚至在JDK演示中也是如此。

    我在一个私人项目中也做了类似的事情。到目前为止,我已经生成了高达1024x1024的图像,没有任何问题(内存除外),并且可以非常快速地显示它们,并且没有任何性能问题

    重写JPanel子类的paint方法是过分的,需要比您需要做的更多的工作

    我的做法是:

    Class MapIcon implements Icon {...}
    

    用于生成图像的代码将在此类中。我使用BuffereImage绘制,然后调用paintIcon()时,使用g.drawImvge(BuffereImage);这减少了生成图像时进行的闪烁量,并且您可以对其执行线程操作

    接下来,我扩展JLabel:

    Class MapLabel extends Scrollable, MouseMotionListener {...}
    
    这是因为我想将图像放在滚动窗格上,即显示图像的一部分,并让用户根据需要滚动

    然后我使用一个JScrollPane来保存MapLabel,它只包含MapIcon

    MapIcon map = new MapIcon (); 
    MapLabel mapLabel = new MapLabel (map);
    JScrollPane scrollPane = new JScrollPane();
    
    scrollPane.getViewport ().add (mapLabel);
    

    但是对于您的场景(每次只需显示整个图像)。您需要将MapLabel添加到顶部JPanel,并确保将它们全部调整为图像的完整大小(通过覆盖GetPreferredSize())

    通过使用免费库中的JXImagePanel类,可以避免完全滚动自己的组件子类


    我认为没有必要对任何东西进行子类化。只需使用Jlabel。可以将图像设置为Jlabel。因此,调整Jlabel的大小,然后用图像填充它。没关系。我就是这样做的

    如果您正在使用JPanels,那么您可能正在使用Swing。试试这个:

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

    该图像现在是一个swing组件。它像任何其他组件一样受布局条件的影响。

    弗雷德·哈斯拉姆的方法很好。不过,我在文件路径方面遇到了问题,因为我想在jar中引用一个图像。为此,我使用了:

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

    因为我只需要使用这种方法加载有限数量(大约10个)的图像,所以效果非常好。它不需要有正确的相对文件路径就可以获取文件。

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

    JLabel imgLabel = new JLabel(new ImageIcon("path_to_image.png"));
    
    我也想在我的jar中引用一个图像,但我没有使用BuffereImage,而是简单地执行了以下操作:

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

    在项目目录中创建一个源文件夹,在本例中,我称之为Images

    JFrame snakeFrame = new JFrame();
    snakeFrame.setBounds(100, 200, 800, 800);
    snakeFrame.setVisible(true);
    snakeFrame.add(new JLabel(new ImageIcon("Images/Snake.png")));
    snakeFrame.pack();
    

    您可以避免使用自己的
    组件
    s和SwingX库以及
    ImageIO
    类:

    File f = new File("hello.jpg");
    JLabel imgLabel = new JLabel(new ImageIcon(file.getName()));
    

    我可以看到很多答案,但并没有真正解决OP的三个问题

    1)性能一词:字节数组可能没有效率,除非您可以使用与显示适配器当前分辨率和颜色深度匹配的精确像素字节顺序

    要获得最佳绘图性能,只需将图像转换为BuffereImage,该图像是使用与当前图形配置对应的类型生成的。请参阅上的createCompatibleImage

    绘制几次后,这些图像将自动缓存在显示卡内存中,无需任何编程工作(这是自Java 6以来Swing的标准配置),因此,如果不更改图像,实际绘制所需的时间可以忽略不计

    改变图像将在主内存和GPU内存之间进行额外的内存传输,这很慢。避免将图像“重绘”到BuffereImage中,因此,尽可能避免执行getPixel和setPixel

    例如,如果您正在开发一个游戏,而不是将所有游戏参与者绘制到一个BuffereImage,然后再绘制到一个JPanel,那么将所有参与者作为较小的BuffereImage加载要快得多,然后在JPanel代码中将它们一个一个地画在适当的位置——这样,除了用于缓存的图像的初始传输之外,主内存和GPU内存之间没有额外的数据传输

    ImageIcon将在引擎盖下使用BuffereImage-但基本上,为BuffereImage分配适当的图形模式是关键,没有任何努力来正确完成这一点

    2)JFrame snakeFrame = new JFrame(); snakeFrame.setBounds(100, 200, 800, 800); snakeFrame.setVisible(true); snakeFrame.add(new JLabel(new ImageIcon("Images/Snake.png"))); snakeFrame.pack();
    File f = new File("hello.jpg");
    JLabel imgLabel = new JLabel(new ImageIcon(file.getName()));
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, this); 
    }